以下是小编整理了面试宝典 程序员面试题精选100题,本文共11篇,希望你喜欢,也可以帮助到您,欢迎分享!本文原稿由网友“cheapa”提供。
篇1:面试宝典 程序员面试题精选100题
前言
随着高校的持续扩张,每年应届毕业生的数目都在不断增长,伴随而来的是应届毕业生的就业压力也越来越大。
在这样的背景下,就业变成一个买方市场的趋势越来越明显。为了找到一个称心的工作,绝大多数应届毕业生都必须反复经历简历筛选、电话面试、笔试、面试等环节。在这些环节中,面试无疑起到最为重要的作用,因为通过面试公司能够最直观的了解学生的能力。
为了有效地准备面试,面经这个新兴概念应运而生。笔者在当初找工作阶段也从面经中获益匪浅并最终找到满意的工作。为了方便后来者,笔者花费大量时间收集并整理散落在茫茫网络中的面经。不同行业的面经全然不同,笔者从自身专业出发,着重关注程序员面试的面经,并从精选出若干具有代表性的技术类的面试题展开讨论,希望能给读者带来一些启发。
由于笔者水平有限,给各面试题提供的思路和代码难免会有错误,还请读者批评指正。另外,热忱欢迎读者能够提供更多、更好的面试题,本人将感激不尽。
(01)把二元查找树转变成排序的双向链表
[折叠]
题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。
比如将二元查找树
10
/
6 14
/ /
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。
思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。
思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。
参考代码:
首先我们定义二元查找树结点的数据结构如下:
struct BSTreeNode // a node in the binary search tree
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
思路一对应的代码:
///////////////////////////////////////////////////////////////////////
// Covert a sub binary-search-tree into a sorted double-linked list
// Input: pNode - the head of the sub tree
// asRight - whether pNode is the right child of its parent
// Output: if asRight is true, return the least node in the sub-tree
// else return the greatest node in the sub-tree
///////////////////////////////////////////////////////////////////////
BSTreeNode* ConvertNode(BSTreeNode* pNode, bool asRight)
{
if(!pNode)
return NULL;
BSTreeNode *pLeft = NULL;
BSTreeNode *pRight = NULL;
// Convert the left sub-tree
if(pNode->m_pLeft)
pLeft = ConvertNode(pNode->m_pLeft, false);
// Connect the greatest node in the left sub-tree to the current node
if(pLeft)
{
pLeft->m_pRight = pNode;
pNode->m_pLeft = pLeft;
}
// Convert the right sub-tree
if(pNode->m_pRight)
pRight = ConvertNode(pNode->m_pRight, true);
// Connect the least node in the right sub-tree to the current node
if(pRight)
{
pNode->m_pRight = pRight;
pRight->m_pLeft = pNode;
}
BSTreeNode *pTemp = pNode;
// If the current node is the right child of its parent,
// return the least node in the tree whose root is the current node
if(asRight)
{
while(pTemp->m_pLeft)
pTemp = pTemp->m_pLeft;
}
// If the current node is the left child of its parent,
// return the greatest node in the tree whose root is the current node
else
{
while(pTemp->m_pRight)
pTemp = pTemp->m_pRight;
}
return pTemp;
}
///////////////////////////////////////////////////////////////////////
// Covert a binary search tree into a sorted double-linked list
// Input: the head of tree
// Output: the head of sorted double-linked list
///////////////////////////////////////////////////////////////////////
BSTreeNode* Convert(BSTreeNode* pHeadOfTree)
{
// As we want to return the head of the sorted double-linked list,
// we set the second parameter to be true
return ConvertNode(pHeadOfTree, true);
}
思路二对应的代码:
///////////////////////////////////////////////////////////////////////
// Covert a sub binary-search-tree into a sorted double-linked list
// Input: pNode - the head of the sub tree
// pLastNodeInList - the tail of the double-linked list
///////////////////////////////////////////////////////////////////////
void ConvertNode(BSTreeNode* pNode, BSTreeNode*& pLastNodeInList)
{
if(pNode == NULL)
return;
BSTreeNode *pCurrent = pNode;
// Convert the left sub-tree
if (pCurrent->m_pLeft != NULL)
ConvertNode(pCurrent->m_pLeft, pLastNodeInList);
// Put the current node into the double-linked list
pCurrent->m_pLeft = pLastNodeInList;
if(pLastNodeInList != NULL)
pLastNodeInList->m_pRight = pCurrent;
pLastNodeInList = pCurrent;
// Convert the right sub-tree
if (pCurrent->m_pRight != NULL)
ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}
///////////////////////////////////////////////////////////////////////
// Covert a binary search tree into a sorted double-linked list
// Input: pHeadOfTree - the head of tree
// Output: the head of sorted double-linked list
///////////////////////////////////////////////////////////////////////
BSTreeNode* Convert_Solution1(BSTreeNode* pHeadOfTree)
{
BSTreeNode *pLastNodeInList = NULL;
ConvertNode(pHeadOfTree, pLastNodeInList);
// Get the head of the double-linked list
BSTreeNode *pHeadOfList = pLastNodeInList;
while(pHeadOfList && pHeadOfList->m_pLeft)
pHeadOfList = pHeadOfList->m_pLeft;
return pHeadOfList;
}
(02)设计包含min函数的栈
[折叠]
题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。
分析:这是去年google的一道面试题。
我看到这道题目时,第一反应就是每次push一个新元素时,将栈里所有逆序元素排序。这样栈顶元素将是最小元素。但由于不能保证最后push进栈的元素最先出栈,这种思路设计的数据结构已经不是一个栈了。
在栈里添加一个成员变量存放最小元素(或最小元素的位置)。每次push一个新元素进栈的时候,如果该元素比当前的最小元素还要小,则更新最小元素。
乍一看这样思路挺好的。但仔细一想,该思路存在一个重要的问题:如果当前最小元素被pop出去,如何才能得到下一个最小元素?
因此仅仅只添加一个成员变量存放最小元素(或最小元素的位置)是不够的。我们需要一个辅助栈。每次push一个新元素的时候,同时将最小元素(或最小元素的位置。考虑到栈元素的类型可能是复杂的数据结构,用最小元素的位置将能减少空间消耗)push到辅助栈中;每次pop一个元素出栈的时候,同时pop辅助栈。
参考代码:
#include
#include
templateclass CStackWithMin
{
public:
CStackWithMin(void) {}
virtual ~CStackWithMin(void) {}
T& top(void);
const T& top(void) const;
void push(const T& value);
void pop(void);
const T& min(void) const;
private:
T>m_data;// theelements of stack
size_t>m_minIndex;// the indicesof minimum elements
};
// get the last element of mutable stack
templateT& CStackWithMin::top
{
return m_data.back();
}
// get the last element of non-mutable stack
templateconst T& CStackWithMin::top() const
{
return m_data.back();
}
篇2:程序员面试题
1:如果一个对象equals另一个对象,那么他们的hashcode一定相同
2:如果一个对象==另一个对象,那么他们的hashcode一定相同
3:instanceof运算符可以用来决定某对象的类是否实现了某个接口
4:Spring/webwork/Hibernate是几个实现MVC的框架
5:运行在一台主机上的服务器进程,其端口号不能重复
6:属于unix主机系统的可热插拔硬盘,在取出硬盘前,必须先将该硬盘的文件系统拆卸unmound下来.
7:HTML是XML
8:Jsp不是servlet
9:数据库触发器的编译代码不在数据库中存储,所以多次触发触发器时,数据库管理系统都
将对触发器进行编译,然后执行它.
10:事务transctions是数据库管理系统进行并发控制的最小单位.
更多与计算机专业相关的面试试题分享,大家可继续阅读:
1、C语言笔试题目及答案
2、网管系统维护工程师面试题
3、网络系统分析工程师传输类笔试题
篇3:面试宝典:《世界500强面试题》
编辑推荐
作者拥有25年世界500强公司面试官经历
首次揭秘名企面试题目 首次曝光名企“群面”细节
助你全面实现“脱颖而出”
内容简介
高超的面试技巧使你在有限的时间内准确无误地展现自己的优势。提高面试技巧的最佳方法是真题演练。
“群面”,又称“群殴”,应用率极高,通过率极低。本书首次重现名企“群面”细节,详细分析“群面”对策。
在形容竞争中的胜出者时,人们常用的一个词是“脱颖而出”。
这也是本书的初衷——“让你脱颖而出”!
目录
序言
第一章 人品测试
——走入名企第一步
第二章 情商测试
——名企员工必备素质
第三章 智商测试
——竞聘名企必需竞争力
第四章 群面
——冲破“群殴”的重围
第五章 世界500强公司面试题库
——面试能力的全方位演练
篇4:程序员网络面试题
题目(一):我们可以用static修饰一个类的成员函数,也可以用const修饰类的成员函数(写在函数的最后表示不能修改成员变量,不是指写在前面表示返回值为常量)。请问:能不能同时用static和const修饰类的成员函数?
分析:答案是不可以。C++编译器在实现const的成员函数的时候为了确保该函数不能修改类的实例的状态,会在函数中添加一个隐式的参数const this*。但当一个成员为static的时候,该函数是没有this指针的。也就是说此时static的用法和static是冲突的。
我们也可以这样理解:两者的语意是矛盾的。static的作用是表示该函数只作用在类型的静态变量上,与类的实例没有关系;而const的作用是确保函数不能修改类的实例的状态,与类型的静态变量没有关系。因此不能同时用它们。
题目(二):运行下面的代码,输出是什么?
class A
{
};
class B
{
public:
B {}
~B() {}
};
class C
{
public:
C() {}
virtual ~C() {}
};
int _tmain(int argc, _TCHAR* argv[])
{
printf(“%d, %d, %d ”, sizeof(A), sizeof(B), sizeof(C));
return 0;
}
分析:答案是1, 1, 4。class A是一个空类型,它的实例不包含任何信息,本来求sizeof应该是0。但当我们声明该类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。至于占用多少内存,由编译器决定。Visual Studio 中每个空类型的实例占用一个byte的空间。
class B在class A的基础上添加了构造函数和析构函数。由于构造函数和析构函数的调用与类型的实例无关(调用它们只需要知道函数地址即可),在它的实例中不需要增加任何信息。所以sizeof(B)和sizeof(A)一样,在Visual Studio 2008中都是1。
class C在class B的基础上把析构函数标注为虚拟函数。C++的编译器一旦发现一个类型中有虚拟函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针。在32位的机器上,一个指针占4个字节的空间,因此sizeof(C)是4。
题目(三):运行下面中的代码,得到的结果是什么?
class A
{
private:
int m_value;
public:
A(int value)
{
m_value = value;
}
void Print1()
{
printf(“hello world”);
}
void Print2()
{
printf(“%d”, m_value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pA = NULL;
pA->Print1();
pA->Print2();
return 0;
}
分析:答案是Print1调用正常,打印出hello world,但运行至Print2时,程序崩溃。调用Print1时,并不需要pA的地址,因为Print1的函数地址是固定的。编译器会给Print1传入一个this指针,该指针为NULL,但在Print1中该this指针并没有用到。只要程序运行时没有访问不该访问的内存就不会出错,因此运行正常。在运行print2时,需要this指针才能得到m_value的值。由于此时this指针为NULL,因此程序崩溃了。
题目(四):运行下面中的代码,得到的结果是什么?
class A
{
private:
int m_value;
public:
A(int value)
{
m_value = value;
}
void Print1()
{
printf(“hello world”);
}
virtual void Print2()
{
printf(“hello world”);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pA = NULL;
pA->Print1();
pA->Print2();
return 0;
}
分析:答案是Print1调用正常,打印出hello world,但运行至Print2时,程序崩溃。Print1的调用情况和上面的题目一样,不在赘述。由于Print2是虚函数。C++调用虚函数的时候,要根据实例(即this指针指向的实例)中虚函数表指针得到虚函数表,再从虚函数表中找到函数的地址。由于这一步需要访问实例的地址(即this指针),而此时this指针为空指针,因此导致内存访问出错。
题目(五):静态成员函数能不能同时也是虚函数?
分析:答案是不能。调用静态成员函数不要实例。但调用虚函数需要从一个实例中指向虚函数表的指针以得到函数的地址,因此调用虚函数需要一个实例。两者相互矛盾。
题目(六):运行下列C++代码,输出什么?
struct Point3D
{
int x;
int y;
int z;
};
int _tmain(int argc, _TCHAR* argv[])
{
Point3D* pPoint = NULL;
int offset = (int)(&(pPoint)->z);
printf(“%d”, offset);
return 0;
}
答案:输出8。由于在pPoint->z的前面加上了取地址符号,运行到此时的时候,会在pPoint的指针地址上加z在类型Point3D中的偏移量8。由于pPoint的地址是0,因此最终offset的值是8。
&(pPoint->z)的语意是求pPoint中变量z的地址(pPoint的地址0加z的偏移量8),并不需要访问pPoint指向的内存。只要不访问非法的内存,程序就不会出错。
题目(七):运行下列C++代码,输出什么?
class A
{
public:
A()
{
Print();
}
virtual void Print()
{
printf(“A is constructed. ”);
}
};
class B: public A
{
public:
B()
{
Print();
}
virtual void Print()
{
printf(“B is constructed. ”);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pA = new B();
pA;
return 0;
}
答案:先后打印出两行:A is constructed. B is constructed. 调用B的构造函数时,先会调用B的基类及A的构造函数。然后在A的构造函数里调用Print。由于此时实例的类型B的部分还没有构造好,本质上它只是A的一个实例,他的虚函数表指针指向的是类型A的虚函数表。因此此时调用的Print是A::Print,而不是B::Print。接着调用类型B的构造函数,并调用Print。此时已经开始构造B,因此此时调用的Print是B::Print。
同样是调用虚拟函数Print,我们发现在类型A的构造函数中,调用的是A::Print,在B的构造函数中,调用的是B::Print。因此虚函数在构造函数中,已经失去了虚函数的动态绑定特性。
题目(八):运行下列C#代码,输出是什么?
namespace ChangesOnString
{
class Program
{
static void Main(string[] args)
{
String str = “hello”;
str.ToUpper();
str.Insert(0, “ WORLD”);
Console.WriteLine(str);
}
}
}
答案:输出是hello。由于在.NET中,String有一个非常特殊的性质:String的实例的状态不能被改变。如果String的成员函数会修改实例的状态,将会返回一个新的String实例。改动只会出现在返回值中,而不会修改原来的实例。所以本题中输出仍然是原来的字符串值hello。
如果试图改变String的内容,改变之后的值可以通过返回值拿到。用StringBuilder是更好的选择,特别是要连续多次修改的时候。如果用String连续多次修改,每一次修改都会产生一个临时对象,开销太大。
题目(九):在C++和C#中,struct和class有什么不同?
答案:在C++中,如果没有标明函数或者变量是的访问权限级别,在struct中,是public的;而在class中,是private的。
在C#中,如果没有标明函数或者变量的访问权限级别,struct和class中都是private的。struct和class的区别是:struct定义值类型,其实例在栈上分配内存;class定义引用类型,其实例在堆上分配内存。
题目(十):运行下图中的C#代码,输出是什么?
namespace StaticConstructor
{
class A
{
public A(string text)
{
Console.WriteLine(text);
}
}
class B
{
static A a1 = new A(“a1”);
A a2 = new A(“a2”);
static B()
{
a1 = new A(“a3”);
}
public B()
{
a2 = new A(“a4”);
}
}
class Program
{
static void Main(string[] args)
{
B b = new B();
}
}
}
答案:打印出四行,分别是a1、a3、a2、a4。
在调用类型B的代码之前先执行B的静态构造函数。静态函数先初始化类型的静态变量,再执行静态函数内的语句。因此先打印a1再打印a3。接下来执行B b = new B(),即调用B的普通构造函数。构造函数先初始化成员变量,在执行函数体内的语句,因此先后打印出a2、a4。
题目(11):运行下图中的C#代码,输出是什么?
namespace StringValueOrReference
{
class Program
{
internal static void ValueOrReference(Type type)
{
String result = “The type ” + type.Name;
if (type.IsValueType)
Console.WriteLine(result + “ is a value type.”);
else
Console.WriteLine(result + “ is a reference type.”);
}
internal static void ModifyString(String text)
{
text = “world”;
}
static void Main(string[] args)
{
String text = “hello”;
ValueOrReference(text.GetType());
ModifyString(text);
Console.WriteLine(text);
}
}
}
答案:输出两行。第一行是The type String is reference type. 第二行是hello。类型String的定义是public sealed class String {...},既然是class,那么String就是引用类型。
在方法ModifyString里,对text赋值一个新的字符串,此时改变的不是原来text的内容,而是把text指向一个新的字符串“world”。由于参数text没有加ref或者out,出了方法之后,text还是指向原来的字符串,因此输出仍然是“hello”.
题目(12):运行下图中的C++代码,输出是什么?
#include
class A
{
private:
int n1;
int n2;
public:
A(): n2(0), n1(n2 + 2)
{
}
void Print()
{
std::cout << “n1: ” << n1 << “, n2: ” << n2 << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
a.Print();
return 0;
}
答案:输出n1是一个随机的数字,n2为0。在C++中,成员变量的初始化顺序与变量在类型中的申明顺序相同,而与它们在构造函数的初始化列表中的顺序无关。因此在这道题中,会首先初始化n1,而初始n1的参数n2还没有初始化,是一个随机值,因此n1就是一个随机值。初始化n2时,根据参数0对其初始化,故n2=0。
题目(13):编译运行下图中的C++代码,结果是什么?(A)编译错误;(B)编译成功,运行时程序崩溃;(C)编译运行正常,输出10。请选择正确答案并分析原因。
#include
class A
{
private:
int value;
public:
A(int n)
{
value = n;
}
A(A other)
{
value = other.value;
}
void Print()
{
std::cout << value << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a = 10;
A b = a;
b.Print();
return 0;
}
答案:编译错误。在复制构造函数中传入的参数是A的一个实例。由于是传值,把形参拷贝到实参会调用复制构造函数。因此如果允许复制构造函数传值,那么会形成永无休止的递归并造成栈溢出。因此C++的标准不允许复制构造函数传值参数,而必须是传引用或者常量引用。在Visual Studio和GCC中,都将编译出错。
题目(14):运行下图中的C++代码,输出是什么?
int SizeOf(char pString[])
{
return sizeof(pString);
}
int _tmain(int argc, _TCHAR* argv[])
{
char* pString1 = “google”;
int size1 = sizeof(pString1);
int size2 = sizeof(*pString1);
char pString2[100] = “google”;
int size3 = sizeof(pString2);
int size4 = SizeOf(pString2);
printf(“%d, %d, %d, %d”, size1, size2, size3, size4);
return 0;
}
答案:4, 1, 100, 4。pString1是一个指针。在32位机器上,任意指针都占4个字节的空间。*pString1是字符串pString1的第一个字符。一个字符占一个字节。pString2是一个数组,sizeof(pString2)是求数组的大小。这个数组包含100个字符,因此大小是100个字节。而在函数SizeOf中,虽然传入的参数是一个字符数组,当数组作为函数的参数进行传递时,数组就自动退化为同类型的指针。因此size4也是一个指针的大小,为4.
题目(15):运行下图中代码,输出的结果是什么?这段代码有什么问题?
#include
class A
{
public:
A()
{
std::cout << “A is created.” << std::endl;
}
~A()
{
std::cout << “A is d.” << std::endl;
}
};
class B : public A
{
public:
B()
{
std::cout << “B is created.” << std::endl;
}
~B()
{
std::cout << “B is d.” << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* pA = new B();
pA;
return 0;
}
答案:输出三行,分别是:A is created. B is created. A is d。用new创建B时,回调用B的构造函数。在调用B的构造函数的时候,会先调用A的构造函数。因此先输出A is created. B is created.
接下来运行语句时,会调用析构函数。由于pA被声明成类型A的指针,同时基类A的析构函数没有标上virtual,因此只有A的析构函数被调用到,而不会调用B的析构函数。
由于pA实际上是指向一个B的实例的指针,但在析构的时候只调用了基类A的析构函数,却没有调用B的析构函数。这就是一个问题。如果在类型B中创建了一些资源,比如文件句柄、内存等,在这种情况下都得不到释放,从而导致资源泄漏。
问题(16):运行如下的C++代码,输出是什么?
class A
{
public:
virtual void Fun(int number = 10)
{
std::cout << “A::Fun with number ” << number;
}
};
class B: public A
{
public:
virtual void Fun(int number = 20)
{
std::cout << “B::Fun with number ” << number;
}
};
int main()
{
B b;
A &a = b;
a.Fun();
}
答案:输出B::Fun with number 10。由于a是一个指向B实例的引用,因此在运行的时候会调用B::Fun。但缺省参数是在编译期决定的。在编译的时候,编译器只知道a是一个类型a的引用,具体指向什么类型在编译期是不能确定的,因此会按照A::Fun的声明把缺省参数number设为10。
这一题的关键在于理解确定缺省参数的值是在编译的时候,但确定引用、指针的虚函数调用哪个类型的函数是在运行的时候。
问题(17):运行如下的C代码,输出是什么?
char* GetString1()
{
char p[] = “Hello World”;
return p;
}
char* GetString2()
{
char *p = “Hello World”;
return p;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf(“GetString1 returns: %s. ”, GetString1());
printf(“GetString2 returns: %s. ”, GetString2());
return 0;
}
答案:输出两行,第一行GetString1 returns: 后面跟的是一串随机的内容,而第二行GetString2 returns: Hello World. 两个函数的区别在于GetString1中是一个数组,而GetString2中是一个指针。
当运行到GetString1时,p是一个数组,会开辟一块内存,并拷贝“Hello World”初始化该数组。接着返回数组的首地址并退出该函数。由于p是GetString1内的一个局部变量,当运行到这个函数外面的时候,这个数组的内存会被释放掉。因此在_tmain函数里再去访问这个数组的内容时,结果是随机的。
当运行到GetString2时,p是一个指针,它指向的是字符串常量区的一个常量字符串。该常量字符串是一个全局的,并不会因为退出函数GetString2而被释放掉。因此在_tmain中仍然根据GetString2返回的地址得到字符串“Hello World”。
问题(18):运行下图中C#代码,输出的结果是什么?
namespace StaticVariableInAppDomain
{
[Serializable]
internal class A : MarshalByRefObject
{
public static int Number;
public void SetNumber(int value)
{
Number = value;
}
}
[Serializable]
internal class B
{
public static int Number;
public void SetNumber(int value)
{
Number = value;
}
}
class Program
{
static void Main(string[] args)
{
String assamblyName = Assembly.GetEntryAssembly().FullName;
AppDomain domain = AppDomain.CreateDomain(“NewDomain”);
A.Number = 10;
String nameOfA = typeof(A).FullName;
A a = domain.CreateInstanceAndUnwrap(assamblyName, nameOfA) as A;
a.SetNumber(20);
Console.WriteLine(“Number in class A is {0}”, A.Number);
B.Number = 10;
String nameOfB = typeof(B).FullName;
B b = domain.CreateInstanceAndUnwrap(assamblyName, nameOfB) as B;
b.SetNumber(20);
Console.WriteLine(“Number in class B is {0}”, B.Number);
}
}
}
答案:输出两行,第一行是Number in class A is 10,而第二行是Number in class B is 20。上述C#代码先创建一个命名为NewDomain的应用程序域,并在该域中利用反射机制创建类型A的一个实例和类型B的一个实例。我们注意到类型A是继承自MarshalByRefObject,而B不是。虽然这两个类型的结构一样,但由于基类不同而导致在跨越应用程序域的边界时表现出的行为将大不相同。
由于A继承MarshalByRefObject,那么a实际上只是在缺省的域中的一个代理,它指向位于NewDomain域中的A的一个实例。当a.SetNumber时,是在NewDomain域中调用该方法,它将修改NewDomain域中静态变量A.Number的值并设为20。由于静态变量在每个应用程序域中都有一份独立的拷贝,修改NewDomain域中的静态变量A.Number对缺省域中的静态变量A.NewDomain没有任何影响。由于Console.WriteLine是在缺省的应用程序域中输出A.Number,因此输出仍然是10。
B只从Object继承而来的类型,它的实例穿越应用程序域的边界时,将会完整地拷贝实例。在上述代码中,我们尽管试图在NewDomani域中生成B的实例,但会把实例b拷贝到缺省的域。此时,调用b.SetNumber也是在缺省的域上进行,它将修改缺省的域上的A.Number并设为20。因此这一次输出的是20。
问题(19):运行下图中C代码,输出的结果是什么?
int _tmain(int argc, _TCHAR* argv[])
{
char str1[] = “hello world”;
char str2[] = “hello world”;
char* str3 = “hello world”;
char* str4 = “hello world”;
if(str1 == str2)
printf(“str1 and str2 are same. ”);
else
printf(“str1 and str2 are not same. ”);
if(str3 == str4)
printf(“str3 and str4 are same. ”);
else
printf(“str3 and str4 are not same. ”);
return 0;
}
答案:输出两行。第一行是str1 and str2 are not same,第二行是str3 and str4 are same。
str1和str2是两个字符串数组。我们会为它们分配两个长度为12个字节的空间,并把“hello world”的内容分别拷贝到数组中去。这是两个初始地址不同的数组,因此比较str1和str2的值,会不相同。str3和str4是两个指针,我们无需为它们分配内存以存储字符串的内容,而只需要把它们指向“hello world“在内存中的地址就可以了。由于”hello world”是常量字符串,它在内存中只有一个拷贝,因此str3和str4指向的是同一个地址。因此比较str3和str4的值,会是相同的。
问题(20):运行下图中C#代码,输出的结果是什么?并请比较这两个类型各有什么特点,有哪些区别。
namespace Singleton
{
public sealed class Singleton1
{
private Singleton1()
{
Console.WriteLine(“Singleton1 constructed”);
}
public static void Print()
{
Console.WriteLine(“Singleton1 Print”);
}
private static Singleton1 instance = new Singleton1();
public static Singleton1 Instance
{
get
{
return instance;
}
}
}
public sealed class Singleton2
{
Singleton2()
{
Console.WriteLine(“Singleton2 constructed”);
}
public static void Print()
{
Console.WriteLine(“Singleton2 Print”);
}
public static Singleton2 Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
static Nested() { }
internal static readonly Singleton2 instance = new Singleton2();
}
}
class Program
{
static void Main(string[] args)
{
Singleton1.Print();
Singleton2.Print();
}
}
}
答案: 输出三行:第一行“Singleton1 constructed”,第二行“Singleton1 Print”,第三行“Singleton2 Print”。
当我们调用Singleton1.Print时,.NET运行时会自动调用Singleton1的静态构造函数,并初始化它的静态变量。此时会创建一个Singleton1的实例,因此会调用它的构造函数。Singleton2的实例是在Nested的静态构造函数里初始化的。只有当类型Nested被使用时,才回触发.NET运行时调用它的静态构造函数。我们注意到我们只在Sington2.Instance里面用到了Nested。而在我们的代码中,只调用了Singleton2.Print。因此不会创建Singleton2的实例,也不会调用它的构造函数。
这两个类型其实都是单例模式(Singleton)的实现。第二个实现Singleton2只在真的需要时,才会创建实例,而第一个实现Singleton1则不然。第二个实现在空间效率上更好。
问题(21):C#是一门托管语言,那么是不是说明只要用C#,就能保证不会出现内存泄露和其他资源泄漏?如果不是,在哪些情况下可能会出现泄漏?
答案:C#不能保证没有资源泄漏。比如如下几种情况可能会造成资源泄漏:(1) 调用Native code,比如用P/Invoke或者调用COM;(2) 读写文件时的,没有及时close stream, 或者ADO.NET连数据库时,没有及时关闭连接,也算资源泄漏?(3)注册事件后没有remove,导致publisher和subscriber的强依 赖,垃圾回收可能会被推迟;(4).NET还定义了一些方法直接申请非托管内存,比如Marshal.AllocHGlobal和Marshal.AllocCoTaskMem。通过这种方式得到的内存,如果没有及时释放,也会造成内存泄露。
问题(22):下面的两段C#有哪些不同?
static void CatchException1()
{
try
{
Function();
}
catch
{
throw;
}
}
static void CatchException2()
{
try
{
Function();
}
catch (Exception e)
{
throw e;
}
}
答案:两个函数的catch都是重新抛出截获的exception,但抛出的exception的call stack是不一样的。对于第一种方法,exception的call stack是从最开始的抛出地点开始的。对于第二种方法,exception的call stack是从CatchException2开始的,最初抛出的地方相关的信息被隐藏了。
问题(23):运行下图中的C++代码,打印出的结果是什么?
bool Fun1(char* str)
{
printf(“%s ”, str);
return false;
}
bool Fun2(char* str)
{
printf(“%s ”, str);
return true;
}
int _tmain(int argc, _TCHAR* argv[])
{
bool res1, res2;
res1 = (Fun1(“a”) && Fun2(“b”)) || (Fun1(“c”) || Fun2(“d”));
res2 = (Fun1(“a”) && Fun2(“b”)) && (Fun1(“c”) || Fun2(“d”));
return res1 || res2;
}
答案:打印出4行,分别是a、c、d、a。
在C/C++中,与、或运算是从左到右的顺序执行的。在计算rest1时,先计算Fun1(“a”) && Func2(“b”)。首先Func1(“a”)打印出内容为a的一行。由于Fun1(“a”)返回的是false, 无论Func2(“b”)的返回值是true还是false,Fun1(“a”) && Func2(“b”)的结果都是false。由于Func2(“b”)的结果无关重要,因此Func2(“b”)会略去而不做计算。接下来计算Fun1(“c”) || Func2(“d”),分别打印出内容c和d的两行。
在计算rest2时,首先Func1(“a”)打印出内容为a的一行。由于Func1(“a”)返回false,和前面一样的道理,Func2(“b”)会略去不做计算。由于Fun1(“a”) && Func2(“b”)的结果是false,不管Fun1(“c”) && Func2(“d”)的结果是什么,整个表达式得到的结果都是false,因此Fun1(“c”) && Func2(“d”)都将被忽略。
问题(24):运行下面的C#代码,打印出来的结果是什么?
struct Person
{
public string Name;
public override string ToString()
{
return Name;
}
}
class Program
{
static void Main(string[] args)
{
ArrayList array = new ArrayList();
Person jim = new Person() {Name = “Jim”};
array.Add(jim);
Person first = (Person)array[0];
first.Name = “Peter”;
Console.WriteLine(array[0].ToString());
}
}
答案:Person的定义是一个struct,因此是一个值类型。在运行到语句Person first = (Person)array[0]的时候,first是array[0]的一个拷贝,first和array[0]不是一个实例。因此修改first对array[0]没有影响。
问题(25):运行下面的C++代码,打印的结果是什么?
class Base
{
public:
void print() { doPrint();}
private:
virtual void doPrint() {cout << “Base::doPrint” << endl;}
};
class Derived : public Base
{
private:
virtual void doPrint() {cout << “Derived::doPrint” << endl;}
};
int _tmain(int argc, _TCHAR* argv[])
{
Base b;
b.print();
Derived d;
d.print();
return 0;
}
答案:输出两行,分别是Base::doPrint和Derived::doPrint。在print中调用doPrint时,doPrint()的写法和this->doPrint()是等价的,因此将根据实际的类型调用对应的doPrint。所以结果是分别调用的是Base::doPrint和Derived::doPrint2。如果感兴趣,可以查看一下汇编代码,就能看出来调用doPrint是从虚函数表中得到函数地址的。
[程序员网络面试题]
篇5:网站程序员面试题
虽然网申没有被短信通知,哥看到笔试通知,还是厚脸皮一溜小跑去了笔试。因为没有在名单上,还得等人都到了才能进入,人其实有点少,除去几个我认识的也没来,还是很少,跟网上说的浙大几千孩子都去笔试有点差距。淘宝面子大了,咱工大孩子面子也大去。软件企业非此一家么,呵呵。
正题吧,说说笔试题。之前还以为会有诸如“令狐冲对岳不群的看法”这样的题目,结果基本都是基础题,还好,本来那些武侠都忘的差不多了…
选择题
第一题,两台电脑在局域网中,机器为千兆网卡,一台作服务器里面有一张网页为1K字节,问另一台下载这个网页的速度。
我答:我不知道1K是指1024还是1000…不过按我的算法没区别,1000 000000/8/1k
我选了10 000张/秒
第二题,单链表插入一个节点的问题。在p指向的节点后插入一个q指向的节点。
我答:q->next=p->next;p->next=q;
之后乱序,我记不清楚题号了。
有一题,地图染色问题,每个国家用矩形表示,让相邻国家颜色不同。离散里面有
有一题,问快速排序达到最坏情况时间复杂度n2的原数数组的具体情形。见数据结构
有一题,很扯的…指针取址符号混乱,选项却很白痴。
有一题,入栈序列1,2,3,4,5,..,n,第一个出栈的是n,问第i个出栈的是多少。
我答:n-i+1
最后一题,给中缀和后缀表达式,求前缀表达式。
填空题
第一题:数组(a1,a2,a3,a4..,an),删除任意一个的概率相同,问平均删除一个要移动多少个。
我答:(n-1)/2
第二题:一个程序填空,程序大意是在数组里面找第二大的数。
注:不难
第三题:大致如下一个程序片段:
void xxx(x)
{
intcountx=0;
while(x)
{
countx++;
x=x&(x-1);
}
cout<
}
问xxx(9999)输出什么。
我答:8,记得做ACM的时候碰到过那个式子,貌似关于排列的,具体意思忘记了,搞一下可以明白是x变成二进制,里面有多少个1就是答案。
篇6:php程序员面试题
请列举你能想到的UNIX信号,并说明信号用途。
请列举、你能想到的所有的字符串查找算法,并加注释简单说明。
有一个IP地址(192.168.0.1),请写出其32位无符号整数形式。
写出、你能想到的所有HTTP返回状态值,并说明用途(比如:返回404表示找不到页面)
向php传入参数的两种方法。
(mysql)请写出数据类型(int char varchar datetime text)的意思; 请问varchar和char有什么区别;
error_reporting 等调试函数使用
您是否用过版本控制软件? 如果有您用的版本控制软件的名字是?
posix和perl标准的正则表达式区别;
Safe_mode 打开后哪些地方受限.
您是否用过模板引擎? 如果有您用的模板引擎的名字是?
请介绍Session的原理,大型网站中Session方面应注意什么?
测试php性能和mysql数据库性能的工具,和找出瓶颈的方法。
您写过的PHP框架的特点,主要解决什么问题,与其他框架的不同点。
sort、assort()、和 ksort() 有什么分别?它们分别在什么情况下使用?
reference 跟一个正规的变量有什么分别?如何 pass by reference?在什么情况下我们需要这样做?
你如何替 PHP 的应用程式侦错?
你如何产生一个 myclass 的物件?
你会如何定义一个没有成员函式或特性的类别 myclass?
给你一行文字 $string,你会如何编写一个正规表达式,把 $string 内的 HTML 标签除去?
PHP 和 Perl 分辨阵列和散列表的方法有什么差异?
篇7:面试宝典:四大常见面试题的分析
你为什么想进入我们公司?你对薪水的期望?等等问题都是面试时候最常问的问题,作为求职者,你知道如何应对这些最基本常见却又不好回答的问题吗?告诉你方法,但是你一定要hold住面试啊!
常见问题一:你为何想进这家公司?
我知道,很多 求职 者肯定会随便挑选个理由,比如说公司培训机会多,发展前景好等公司能给到我什么的角度去说。但是这样的回答是不妥的。
最好的回答应该是,不要只谈希望公司给你提供多少福利、培训,而应让对方觉得你能为公司创造价值。
常见问题二:你认为你适合干什么?
有些太直言不讳,不经过脑袋就放话的 求职 者会说:“只要公司需要,我什么都能干。”
你真的什么都能干?你是个通才?你未免高估自己了!你必须让人觉得你有抱负,但也脚踏实地,
你觉得自己最适合干什么,就老实告诉人家,“服从需要”之类的空话,效果适得其反。
常见问题三:你对薪水的期望值如何?
很多求职者会直接说一个数字,这样贸然回答是最不妥的回答。
记住了,即使对方问你对薪水的期望,你也应谨慎应对。你可以说,根据行业的情况以及我自己工作的体现,我相信贵公司会给我一个合理的薪水的。
常见问题四:你可以向我提一个关于公司的问题
面试 的最后,有些HR或者公司领导者会让求职者问他们一个问题,而有些求职者就直接问薪水了,比如我能拿到多少钱?某某公司是不是你们的分支机构?
好的问题是:以你的个人经验,你认为新员工要学些什么,会遇到哪些困难?在公司里,我的发展机会如何?公司与某公司(竞争对手)相比,有哪些长处和短处?能否简单介绍一下公司文化?
看似简单的问题,但回答起来却是不简单的,不一样的答案却会对于你是否被录用却有着天壤之别,每一句都是艺术的表现,我们应该努力学习更多如何使用“艺术“更为确当!
篇8:软件测试面试题宝典
你为什么选择软件测试行业?
因为之前了解软件测试这个行业,觉得他的发展前景很好。
根据你以前的工作或学习经验描述一下软件开发、测试过程,由哪些角色负责,你做什么
要有架构师、开发经理、测试经理、程序员、测试员。我在里面主要是负责所分到的模块执行测试用例。
你的测试职业发展是什么?
测试经验越多,测试能力越高。所以我的职业发展是需要时间积累的,一步步向着高级测试工程师奔去。而且我也有初步的职业规划,前3年积累测试经验,按如何做好测试工程师的要点去要求自己,不断更新自己改正自己,做好测试任务。
你认为测试人员需要具备哪些素质?
做测试应该要有一定的协调能力,因为测试人员经常要与开发接触处理一些问题,如果处理不好的话会引起一些冲突,这样的话工作上就会不好做。还有测试人员要有一定的耐心,有的时候做测试很枯燥乏味。除了耐心,测试人员不能放过每一个可能的错误。
你为什么能够做测试这一行?
虽然我的测试技术还不是很成熟,但是我觉得我还是可以胜任软件测试这个工作的,因为做软件测试不仅是要求技术好,还有有一定的沟通能力,耐心、细心等外在因素。综合起来看我认为我是胜任这个工作的。
测试的目的是什么?
测试的目的是找出软件产品中的错误,是软件尽可能的符合用户的要求。当然软件测试是不可能找出全部错误的。
测试分为哪几个阶段?
一般来说分为5个阶段:单元测试、集成测试、确认测试、系统测试、验收测试
单元测试的测试对象、目的、测试依据、测试方法?
测试对象是模块内部的程序错误,目的是消除局部模块逻辑和功能上的错误和缺陷。测试依据是模块的详细设计,测试方法是采用白盒测试。
怎样看待加班问题?
加班的话我没有太多意见,但是我还是觉得如果能够合理安排时间的话,不会有太多时候加班的。
结合你以前的学习和工作经验,你认为如何做好测试?
根据我以前的工作和学习经验,我认为做好工作首先要有一个良好的沟通,只有沟通无障碍了,才会有好的协作,才会有更好的效率,再一个就是技术一定要过关,做测试要有足够的耐心,和一个良好的工作习惯,不懂的就要问,实时与同事沟通这样的话才能做好测试工作。
根据你的经验说说你对软件测试/质量保证的理解
软件质量保证与测试是根据软件开发阶段的规格说明和程序的内部结构而精心设计的一批测试用例(即输入数据和预期的输出结果),并根据这些测试用例去运行程序,以发现错误的过程。它是对应用程序的各个方面进行测试以检查其功能、语言有效性及其外观排布。
软件测试的流程是什么?
需求调查:全面了解系统概况、应用领域、软件开发周期、软件开发环境、开发组织、时间安排、功能需求、性能需求、质量需求及测试要求等。根据系统概况进行项目所需的人员、时间和工作量估计以及项目报价。
制定初步的项目计划。
测试准备:组织测试团队、培训、建立测试和管理环境等。
测试设计:按照测试要求进行每个测试项的测试设计,包括测试用例的设计和测试脚本的开发等。
测试实施:按照测试计划实施测试。
测试评估:根据测试的结果,出具测试评估报告。
篇9:软件测试面试题宝典
问:你在测试中发现了一个 bug ,但是开发经理认为这不是一个 bug ,你应该怎样解决。
首先,将问题提交到缺陷管理库里面进行备案。然后,要获取判断的依据和标准:
根据需求说明书、产品说明、设计文档等,确认实际结果是否与计划有不一致的地方,提供缺陷是否确认的直接依据;如果没有文档依据,可以根据类似软件的一般特性来说明是否存在不一致的地方,来确认是否是缺陷;根据用户的一般使用习惯,来确认是否是缺陷;与设计人员、开发人员和客户代表等相关人员探讨,确认是否是缺陷;合理的论述,向测试经理说明自己的判断的理由,注意客观、严谨,不参杂个人情绪。等待测试经理做出最终决定,如果仍然存在争议,可以通过公司政策所提供的渠道,向上级反映,并有上级做出决定。
问:给你一个网站,你如何测试?
首先,查找需求说明、网站设计 m 等相关文档,分析测试需求。
制定测试计划,确定测试范围和测试策略,一般包括以下几个部分:
功能性测试;界面测试;性能测试;数据库测试;安全性测试;兼容性测试
设计测试用例:
功能性测试可以包括,但不限于以下几个方面:
链接测试。链接是否正确跳转,是否存在空页面和无效页面,是否有不正确的出错信息返回等。
提交功能的测试。
多媒体元素是否可以正确加载和显示。
多语言支持是否能够正确显示选择的语言等。
界面测试可以包括但不限于一下几个方面:
页面是否风格统一,美观页面布局是否合理,重点内容和热点内容是否突出控件是否正常使用,对于必须但为安装的空间,是否提供自动下载并安装的功能
文字检查
性能测试一般从以下两个方面考虑:
压力测试;负载测试;强度测试
数据库测试要具体决定是否需要开展。数据库一般需要考虑连结性,对数据的存取操作,数据内容的验证等方面。
安全性测试:
1 基本的登录功能的检查 2 是否存在溢出错误,导致系统崩溃或者权限泄露 3 相关开发语言的常见安全性问题检查,例如 SQL 注入等。4 如果需要高级的安全性测试,确定获得专业安全公司的帮助,外包测试,或者获取支持兼容性测试,根据需求说明的内容,确定支持的平台组合:浏览器的兼容性;操作系统的兼容性;软件平台的兼容性;数据库的兼容性开展测试,并记录缺陷。合理的安排调整测试进度,提前获取测试所需的资源,建立管理体系(例如,需求变更、风险、配置、测试文档、缺陷报告、人力资源等内容)。
定期评审,对测试进行评估和总结,调整测试的内容。
在搜索引擎中输入汉字就可以解析 到对应的域名,请问如何用 r LoadRunner 进行测试。
建立测试计划,确定测试标准和测试范围
设计典型场景的测试用例,覆盖常用业务流程和不常用的业务流程等
根据测试用例,开发自动测试脚本和场景:
录制测试脚本
新建一个脚本(Web/HTML 协议)
点击录制按钮,在弹出的对话框的 URL 中输入”about:blank”。
在打开的浏览器中进行正常操作流程后,结束录制。
调试脚本并保存。可能要注意到字符集的关联。
设置测试场景
针对性能设置测试场景,主要判断在正常情况下,系统的平均事务响应时间是否达标
针对压力负载设置测试场景,主要判断在长时间处于满负荷或者超出系统承载能力的条件下,系统是否会崩溃。
执行测试,获取测试结果,分析测试结果
问:一台客户端有三百个客户与三百个客户端有三百个客户对服务器施压,有什么区别? ?
300 个用户在一个客户端上,会占用客户机更多的资源,而影响测试的结果。
线程之间可能发生干扰,而产生一些异常。
300 个用户在一个客户端上,需要更大的带宽。
IP 地址的问题,可能需要使用 IP Spoof 来绕过服务器对于单一 IP 地址最大连接数的限制。
所有用户在一个客户端上,不必考虑分布式管理的问题;而用户分布在不同的客户端上,需要考虑使用控制器来整体调配不同客户机上的用户。同时,还需要给予相应的权限配置和防火墙设置。
试述软件的概念和特点?软件复用的含义?构件包括哪些?
软件是计算机系统中与硬件相互依存的另一部分,它是包括程序、文档的完整集合。
软件复用(Software Reuse)是将已有软件的各种有关知识用于建立新的软件,以缩减软件开发和维护的花费。软件复用是提高软件生产力和质量的一种重要技术。早期的软件复用主要是代码级复用,被复用的知识专指程序,后来扩大到包括领域知识、开发经验、设计决定、体系结构、需求、设计、代码和文档等一切有关方面。可以被复用的软件成分一般称作可复用构件
软件生存周期及其模型是什么?
软件生存周期是软件开发全部过程、活动和任务的结构框架,是从可行性研究到需求分析、软件设计、编码、测试、软件发布维护的过程。
在经历需求、分析、设计、实现、部署后,软件将被使用并进入维护阶段,直到最后由于缺少维护费用而逐渐消亡。这样的一个过程,称为“生命周期模型”(Life Cycle Model)。
什么是软件测试?软件测试的目的与原则
使用人工或自动手段,来运行或测试某个系统的过程。其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。
软件测试的目的:
测试是程序的执行过程,目的在于发现错误
一个成功的测试用例在于发现至今未发现的错误
一个成功的测试是发现了至今未发现的错误的测试
确保产品完成了它所承诺或公布的功能,并且用户可以访问到的功能都有明确的书面说明。
确保产品满足性能和效率的要求
确保产品是健壮的和适应用户环境的
软件测试的原则:
教材的说法:
软件测试应尽早执行,并贯穿于整个软件生命周期
软件测试应追溯需求
测试应由第三方来构造
穷举测试是不可能的,要遵循 Good-enough 原则
必须确定预期输出(或结果)
必须彻底检查每个测试结果
充分注意测试中的群集现象
缺陷的二八定理
严格执行测试计划,排除测试的随意性
注意合法合理的输入,也要注意非法的非预期的输入
检查程序是否做了不该做的测试应从“小规模”开始,逐步转向“大规模”反复使用同样的测试会使软件具有抵抗力关注缺陷的修复
软件配置管理的作用?软件配置包括什么?
软件配置管理作为软件开发过程的必要环节和软件开发管理的基础,贯穿整个软件生命周期,同时对软件开发过程的宏观管理即项目管理也有重要的支持作用。一个软件开发组织真正有效的实施软件配置管理,将会使软件开发过程有更好的可预测性,使系统具有可重复性,大大提高软件组织的竞争力。
软件配置包括如下内容:
配置项识别
工作空间管理
版本控制
变更控制
状态报告
配置审计
什么是软件质量?
软件质量:软件产品的特性可以满足用户的功能、性能需求的能力。
篇10:黑马程序员_7K面试题
------- android培训、java培训、期待与您交流! ----------
昨天熬到很晚终于把两个面试题给搞定了,代码是一步一步跟着敲得,大概知道怎么回事了,再看两遍应该会更透彻一些,这两个视频中,我认为重要的是面向对象编程的思想,代码知识跟着思想一步一步敲出来的,思路清晰了,代码自然就不是问题了。张老师反复的一句话很重要:谁拥有数据,谁就对外提供操作这些数据的方法。(一定要牢记)刚开始理解的不太深刻,但越来越发现这句话的重要性。我一定要赶上17期的末班车!!
交通灯管理系统
一.需求:
模拟实现十字路口的交通灯管理系统逻辑,具体需求如下:
1、异步随机生成按照各个路线行驶的车辆。
例如:
由南向而来去往北向的车辆 ---- 直行车辆
由西向而来去往南向的车辆 ---- 右转车辆
由东向而来去往南向的车辆 ---- 左转车辆
。。。
2、信号灯忽略黄灯,只考虑红灯和绿灯。
3、应考虑左转车辆控制信号灯,右转车辆不受信号灯控制。
4、具体信号灯控制逻辑与现实生活中普通交通灯控制逻辑相同,不考虑特殊情况下的控制逻辑。
注:南北向车辆与东西向车辆交替放行,同方向等待车辆应先放行直行车辆而后放行左转车辆。
5、每辆车通过路口时间为1秒(提示:可通过线程Sleep的方式模拟)。
6、随机生成车辆时间间隔以及红绿灯交换时间间隔自定,可以设置。
7、不要求实现GUI,只考虑系统逻辑实现,可通过Log方式展现程序运行结果。
二.画图非常有助于理解和分析问题。图如下:
总共有12条路线,为了统一编程模型,可以假设每条路线都有一个红绿灯对其进行控制,
右转弯的4条路线的控制灯可以假设称为常绿状态,另外,其他的8条线路是两两成对的,可以归为4组,
所以,程序只需考虑图中标注了数字号的4条路线的控制灯的切换顺序,
这4条路线相反方向的路线的控制灯跟随这4条路线切换,不必额外考虑。
三.面向对象的分析与设计
1、每条路线上都会出现多辆车,路线上要随机增加新的车,在灯绿期间还要每秒钟减少一辆车。
(1)、设计一个Road类来表示路线,每个Road对象代表一条路线,总共有12条路线,即系统中总共要产生12个Road实例对象。
(2)、每条路线上随机增加新的车辆,增加到一个集合中保存。
(3)、每条路线每隔一秒都会检查控制本路线的灯是否为绿,是则将本路线保存车的集合中的第一辆车移除,即表示车穿过了路口。
2、每条路线每隔一秒都会检查控制本路线的灯是否为绿,一个灯由绿变红时,应该将下一个方向的灯变绿。
(1)、设计一个Lamp类来表示一个交通灯,每个交通灯都维护一个状态:亮(绿)或不亮(红),每个交通灯要有变亮和变黑的方法,
并且能返回自己的亮黑状态。
(2)、总共有12条路线,所以,系统中总共要产生12个交通灯。右拐弯的路线本来不受灯的控制,
但是为了让程序采用统一的处理方式,故假设出有四个右拐弯的灯,只是这些灯为常亮状态,即永远不变黑。
(3)、除了右拐弯方向的其他8条路线的灯,它们是两两成对的,可以归为4组,所以,在编程处理时,
只要从这4组中各取出一个灯,对这4个灯依次轮询变亮,与这4个灯方向对应的灯则随之一同变化,
因此Lamp类中要有一个变量来记住自己相反方向的灯,在一个Lamp对象的变亮和变黑方法中,将对应方向的灯也变亮和变黑。
每个灯变黑时,都伴随者下一个灯的变亮,Lamp类中还用一个变量来记住自己的下一个灯。
(4)、无论在程序的什么地方去获得某个方向的灯时,每次获得的都是同一个实例对象,所以Lamp类改用枚举来做显然具有很大的方便性,
永远都只有代表12个方向的灯的实例对象。
(5)、设计一个LampController类,它定时让当前的绿灯变红。
3、我们初步设想一下有哪些对象:红绿灯,红绿灯的控制系统,汽车,路线。汽车看到自己所在路线对应的灯绿了就穿过路口吗?
不是,还需要看其前面是否有车,看前面是否有车,该问哪个对象呢?该问路,路中存储着车辆的集合,
显然路上就应该有增加车辆和减少车辆的方法了。再看题目,我们这里并不要体现车辆移动的过程,只是捕捉出车辆穿过路口的过程,
也就是捕捉路上减少一辆车的过程,所以,这个车并不需要单独设计成为一个对象,用一个字符串表示就可以了。
面向对象设计把握一个重要的经验:谁拥有数据,谁就对外提供操作这些数据的方法。再牢牢掌握几个典型的案例就可以了:
人在黑板上画圆,列车司机紧急刹车,售货员统计收获小票的金额,你把门关上了等。
学员的两个面向对象的面试题,用面向对象的方式设计如下情景。
“两块石头磨成一把石刀,石刀可以砍树,砍成木材,木材做成椅子”,
“球从一根绳子的一段移动到了另一端”,
四.Road类的编写
1、每个Road对象都有一个name成员变量来代表方向,有一个vehicles成员变量来代表方向上的车辆集合。
2、在Road对象的构造方法中启动一个线程每隔一个随机的时间向vehicles集合中增加一辆车(用一个“路线名_id”形式的字符串进行表示)。
3、在Road对象的构造方法中启动一个定时器,每隔一秒检查该方向上的灯是否为绿,是则打印车辆集合和将集合中的第一辆车移除掉。
4、在讲Road对象的定时器代码时,因为开始阶段还没有设计Lamp类,所以,检查该方向上的灯是否为绿的代码暂时先采用短路方式。
五.Lamp类的编写
1、系统中有12个方向上的灯,在程序的其他地方要根据灯的名称就可以获得对应的灯的实例对象,综合这些因素,
将Lamp类用java5中的枚举形式定义更为简单。
2、每个Lamp对象中的亮黑状态用lighted变量表示,选用S2N、S2W、E2W、E2N这四个方向上的Lamp对象依次轮询变亮,
Lamp对象中还要有一个oppositeLampName变量来表示它们相反方向的灯,再用一个nextLampName变量来表示此灯变亮后的下一个变亮的灯。
这三个变量用构造方法的形式进行赋值,因为枚举元素必须在定义之后引用,所以无法再构造方法中彼此相互引用,
所以,相反方向和下一个方向的灯用字符串形式表示。
3、增加让Lamp变亮和变黑的方法:light和blackOut,对于S2N、S2W、E2W、E2N这四个方向上的Lamp对象,
这两个方法内部要让相反方向的灯随之变亮和变黑,blackOut方法还要让下一个灯变亮。
4、除了S2N、S2W、E2W、E2N这四个方向上的Lamp对象之外,其他方向上的Lamp对象的nextLampName和oppositeLampName属性设置为null即可,
并且S2N、S2W、E2W、E2N这四个方向上的Lamp对象的nextLampName和oppositeLampName属性必须设置为null,
以便防止light和blackOut进入死循环。
六.LampController类的编写
1、整个系统中只能有一套交通灯控制系统,所以,LampController类最好是设计成单例。
2、LampController构造方法中要设定第一个为绿的灯。
3、LampController对象的start方法中将当前灯变绿,然后启动一个定时器,每隔10秒将当前灯变红和将下一个灯变绿。
七.MainClass类的编写
1、用for循环创建出代表12条路线的对象。
2、接着再获得LampController对象并调用其start方法。
3、String [] directions = {“S2N”,“N2S”,“S2W”,“N2E”,“E2W”,“W2E”,
“E2S”,“W2N”,“S2W”,“N2W”,“E2N”,“W2S”};
刚开始把上面的倒数第4个元素写错了(应该写成S2E),所以总是只看到5个方向上有车通过的情况。
八.代码(代码都是自己敲的所以注释自己写的不太专业,只是为了自己理解。。。)
Road类
package com.isoftstone.interview.traffic;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Road {
private Listvechicles = new ArrayList;
private String name = null;
public Road(String name){
this.name = name;
//定义一个线程池
ExecutorService pool = Executors.newSingleThreadExecutor();
//用池来提交任务
pool.execute(new Runnable(){
//启动线程
public void run(){
for(int i=1;i<1000;i++){
try {
//隔多少秒出现一辆车 1-10秒
Thread.sleep((new Random().nextInt(10) + 1) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//name访问内部类成员变量
vechicles.add(Road.this.name + “_” + i);
}
}
});
//做定时器
ScheduledExecutorService timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(
new Runnable(){
//把集合里的第一辆车移走
public void run(){
//有车
if(vechicles.size(
[黑马程序员_7K面试题]
篇11:java程序员面试题及答案
1、数据库
表a和表b具有完全相同的结构,主键为indexid。写出一个sql语句把表b中不存在而表a中存在的数据插入到表b中。
2、javascript部分
页面中有一个名称都为unitprice的type=text对象。要求输入的数据不能为空,写一个函数实现该功能,如果为空时给出提示。
3、JSP部分
①session中存储一个String变量,变量名称为studentname,写出在jsp中如何得到这个session变量的值的语句。
②在jsp中引用使用来引用javabean.
Ⅰscope的值有哪些,这些值的区别是什么?
Ⅱ不同的jsp页面中引用javabean时,id能否相同,如果能相同,对scope的值有什么要求?
4、JAVA部分
①输入一个维数,输出以下形式的矩阵和数列,以维数n=4为例:
0000
0111
0122
0123
②写出下面这段程序的运行结果
int a=2,b=3,c=1
a+=Cb+c;
c-=b+a++;
System.out.println(“a=”+a+”,b=”+b+”,c=”+c);
5、有一个Vector对象,其中每一个元素都是一个String对象,请用for循环或while循环输出Vector中的元素,要求格式为:”第i个元素为:aaa”
6、有一个HashMap其中key为String对象,value为Integer对象,写一个方法打印出此Map中的所有键值 对形如 keyCvalue
7、有一个String str=”001,A001;002,A002;003,A003″的串,写一个方法,把此串存入列 一个HashMap或Hashtable中,说明:如001为key,A001则为value。
8、面向对象概念:
①面向对象基本特征
②什么叫多态和重载,它们有什么区别?
③用你自己的话描述你理解的j2ee的本质特征是什么?
第一题: 写一个方法,实现删除链表中某个节点的操作(其他条件自己假设,补充)
public void ()
{
if(front>=rear)
{
s[front] =0;
frontC;
System.out.println(“ successful”);
}
else
{
System.out.println(“the link is empty ,can’t ”);
}
}
第二题: 写一个方法,实现堆栈的入栈操作 (其他条件自己假设,补充)
public class stack{
private int[] s;
int top,bottom;
public stack(int size){
s = new int[size];
top = size-1;
bottom = size-1;
System.out.println(“Size of the stack is:”+size);
}
public boolean isEmpty()
{
if(top==s.length-1)
return true;
else
return false;
}
public void push(int n)
{
if(top<0)
{
System.out.println(“The stack is full now,you can’t push your data!”);
return;
}
else
{
s[top] = n;
topC;
return ;
}
}
public void pop()
{
if(top>=s.length-1)
{
System.out.println(“The stack is empty,Can’t pop now!”);
return;
}
else
{
top++;
}
}
public void print()
{
System.out.println(“State of the stack:”);
for(int i=s.length-1;i>top;iC)
{
System.out.print(s[i]+” ”);
}
}
public static void main(String[] a)
{
stack st = new stack(5);
System.out.println(“List of the action to the stack:”);
System.out.println(“push(3):”);
st.push(3);
st.print();
System.out.println(” ”);
System.out.println(“push(6)”);
st.push(6);
st.print();
System.out.println(” ”);
System.out.println(“push(10)”);
st.push(10);
st.print();
System.out.println(” ”);
System.out.println(“pop()”);
st.pop();
st.print();
System.out.println(” ”);
}
}
第三题: 使用任意排序算法,写一个排序示例程序
import java.io.*;
class SelectionSort{
public static void main(String[] args){
int[] a={4,54,8,7,6,98,42,};
sort(a);
for(int i=0;i
System.out.print(a[i]+” “);
}
System.out.println(“”);
}
static void sort(int[] data){
int next, indexOfNext=0,n;
for (next=0;next
{
indexOfNext=min(data,next,(data.length)-1);
swap(data,indexOfNext,next);
}
}
static int min(int[] data,int start,int end){
int indexOfMin=start;
for (int i=start+1;i<=end;i++)
if(data[i]
indexOfMin=i;
return indexOfMin;
}
static void swap(int[] data,int first,int second){
int temp;
temp=data[first];
data[first]=data[second];
data[second]=temp;
}
}
第四题:
编写一个servlet,把servlet源码和此servlet在服务器上的配置文件web.xml作为附件发送到指定的邮箱
servlet的功能要求:记录访问该servlet的客户端的ip和访问时间,把记录写入client_ip.log文件。 client_ip.log里的格式大致如下:
9:36 2005-4-8 192.168.0.1
9:36 2005-4-8 127.0.0.1
获取客户的IP地址
第五题
数据库中有两个表tableA和tableB,他们都有一个int型的字段id,请写出一个sql语句,实现查询id在tableA中有,而tableB中没有的记录
例如tableA中有如下记录
―――――――――-
tableA.id tableA.name
3 Mary
4 Jack
5 Lily
―――――――――-
tableB.id
3
5
查询的结果应该是
―――――――――-
tableA.id tableA.name
4 Jack
select *
from tableA
where not exists
(select *
from tableB
where tableA.id=tableB.id)
第六题 简述jsp和servlet的联系
Java Servlet是JSP技术的基础,而且大型的Web应用程序的开发需要Java Servlet和JSP配合才能完成。现在许多Web服务器都支持Servlet,即使不直接支持Servlet的Web服务器,也可以通过附件的应用服务器和模块来支持Servlet,这得益于Java的跨平台特性。另外,由于Servlet内部以线程方式提供提供服务,不必对于每个请求都启动一个进程,并且利用多线程机制可以同时为多个请求服务,因此Servlet的效率非常高。
第七题 什么是sql注入漏洞,采用什么方法来堵住sql注入漏洞
随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。但是由于这个行业的入门门槛不高,程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入
第八题:简述你对xml的认识,举例说明xml能干什么,应该怎么做
XML是Extensible Markup Language的缩写,意思是可扩展置标语言没有于置标电子文档,使起数据具有结构化的置标语言。在我目前浅显的认识里:,
XML 是用来传递数据的 ,
XML 让这些数据有了结构 ― 一个树型结构 ,
xml 有全套的操作这种结构的方法
xml 规范(或者说的实际点,xml parser)帮你确定你创建的字符串是合法的
xml 规范(或者说的实际点,xml parser)中有办法验证这个合法性
对于XML能用来做什么,我觉得XML可以用来下面几个方面
1:有利于开发灵活的web应用软件
使用XML来描述数据,可以使数据具有同意的组织结构,其他应用软件,对象,中间层和服务器都可以对使用XML描述的数据做进一步的处理。并可以提交到浏览器中让读者阅读
2:可以轻松的实现数据在web上发布
因为XML本身是纯文本格式的,它可以不做任何修改就和HTML文档一样在网络中传输。
3:有利于信息的集成
因为使用XML,可以把不同来源的结构化数据很容易地组织到一起。应用软件可以在中间层的服务器上对来自于后段数据库和其他的数据进行集成。最后,数据以XML格式发送到客户端或者是在其他服务器做进一步处理。
4:可以使用丰富的样式来显示数据
XML采用结构化的方式来组织数据,描述的是数据本身,不涉及到数据的表现形式。通常来说,使用CSS和 XSL以及XSLT为数据的显示提供分布的机制,也就是说数据的显示方式可以根据客户的要求制定。
5:可大大增强服务器的可伸缩性
XML将数据本身和数据的显示完全分离,从而可以在结构化的数据中嵌套数据的显示方式描述。这样,能尽可能地减少客户端与服务器之间的数据交换,减少服务器的工作量才能大大提高服务器的性能。
6:采用统一的XML文档格式来描述多种应用的数据
7:支持本地数据处理
因为XML文档中的数据格式是统一的,当客户受到数据后,便可以使用客户自己的应用软件来解析数据,并对数据进行进一步的编辑和处理。
8:可以使搜索变得更加简单
[java程序员面试题及答案]
- 公务员考试面试通关宝典2021-09-27
- 面试英语:面试宝典求职理由2023-08-25
- 英语面试宝典求职理由2024-11-08
- 面试技巧:有趣而刁钻的面试题2022-12-11
- 面试计算机程序员经典题目2022-12-11
- java程序员面试之葵花宝典2023-03-17
- java程序员面试自我介绍1分钟2023-11-17
- Delphi程序员笔试真题2025-02-24
- 面试宝典:最常问问题和最佳答案2021-11-05
- 公务员面试专家评析四川省面试题2021-11-07