.net程序员面试宝典

《.NET程序员面试宝典》是2009年由电子工业出版社出版的图书,作者是欧立奇。本书主要讲述的是程序员面试的技巧和如何拥有一个乐观的态度。
- 书名 .NET程序员面试宝典
- 作者 欧立奇
- 出版社 电子工业出版社
- 出版时间 2009年01月
- ISBN 978-7-121-06540-8
内容简介
揭开知名IT企业面试、笔试的核心机密,传授程序员岗位求职的关键技巧,传递快乐工作的精神与态度。
《.NET程序员面试宝典》涉猎各大IT公司历年面试真题(包括笔试题、口试题、电话面试、英语面试,以及逻辑测试和智力测试),通过精确详细的分类,把在应聘程序员(含网络、测试等)过程中所遇见的常见考点为你一一点破。
《.NET程序员面试宝典》分为6部分,主要内容包括:求职过程,C#程序设计,数据结构和软件工程,UNIX、Oracle和网络,.NET扩展项目,综合面试题等。最后《.NET程序员面试宝典》着力讲述了如何进行英语面试和电话面试,并给出了大量实际英语面试中的问题、参考答案及常用词汇,尝试解决程序员应聘外企时语言问题造成的瓶颈。《.NET程序员面试宝典》的面试题除了有详细解析和回答外,对相关知识点还有扩展说明。希望真正做到由点成线,举一反三,对读者从求职就业到提升计算机专业知识都有显著帮助。
许多面试看似简单
却需要深厚的基本功才能给出完美的答案
我们能真正写好一段C#归并排序代码吗?
我们都觉得自己能
可是我们写出的代码很可能只能拿到10分中的2分……
《.NET程序员面试宝典》将告诉你如何提高自身功力
以从容面对企业的面试
《.NET程序员面试宝典》要点:
求职过程
.NET程序设计
数据结构与设计模式
操作系统,数据库与网络、软件测试
英语面试,电话面试与智力测试
如果你的简历上写着:"本人精通C#编程、.NET体系;熟悉设计模式、数据结构。"并且自认足够机智,还能在工小时内对下列问题给出准确的答案.那么.毫无疑问你可以通过多数,NE丁程序员面试了。
(1)const和staticreadonly的区别是什么?
(2)XmlSerializer如何工作?
(3)静态构造函数是否可使用this?
(4)实现C#归并排序。
(5)写一个事件:饮水机没水时,A或B或其他人给它加水。
(6)"不要和陌生人说话"是设计模式中哪种原则的通俗表达?
(7)解释UML中的4个名词:依赖、聚合、泛化和关联。
(8)对象实现了Finalize将对垃圾收集有何影响?
(9)描述你对.NETFramework2.0中匿名方法的认识。
(10)1000瓶药水至多有l瓶含剧毒.给你10只狗,在24小时内通过给狗试药的方式找出哪瓶药水有毒或者全部无毒(狗服药X小时后毒发,19<X<23)。
如果,你还不能对上面大部分题目立刻给出准确的答案,甚至还茫无头绪,那或许《.NET程序员面试宝典》将有效弥补你在.NET程序员面试中的缺项,并构造完备的知识体系。
目录
第一部分:求职过程 - 4 -
第1章:应聘求职 - 4 -
1.1【渠道】 - 5 -
1.2【流程】 - 5 -
1.3【职位】 - 6 -
第2章:求职五步曲 - 7 -
2.1【笔试】 - 7 -
2.2【电话面试】 - 11 -
2.3【面试】 - 11 -
2.4【签约】 - 12 -
2.5【违约】 - 17 -
第3章:简历书写 - 18 -
3.1【简历注意事项】 - 18 -
3.2【简历模版】 - 19 -
第4章:职业生涯发展规划 - 24 -
4.1【缺乏工作经验的应届生】 - 24 -
4.2【更换工作的程序员们】 - 26 -
4.3【快乐的工作】 - 26 -
第二部分:C#程序设计 - 28 -
第5章:C#程序设计基本概念 - 28 -
5.1【常见概念】 - 29 -
5.2【C++和C#区别】 - 31 -
5.3【数据类型】 - 31 -
5.4【extern】 - 39 -
5.5【其它】 - 39 -
第6章:const异常 反射 - 40 -
6.1【const】 - 40 -
6.2【异常】 - 42 -
6.3【反射】 - 44 -
第7章:传递与引用 - 49 -
7.1【传值】 - 50 -
7.2【静态变量与私有变量】 - 51 -
7.3【输入输出流】 - 51 -
7.4【程序集】 - 52 -
7.5【序列化】 - 53 -
第8章 循环,条件,概率面试例题 - 54 -
8.1【foreach】 - 54 -
8.2【递归与回朔】 - 56 -
8.3【条件语言】 - 60 -
8.4【随机数】 - 61 -
第9章:关于面向对象的面试问题 - 63 -
9.1【面向对象的基本概念】 - 63 -
9.2【访问修饰符】 - 65 -
9.3【类和结构】 - 67 -
9.4【Static】 - 72 -
9.5【密封类】 - 75 -
9.6【构造函数和析构函数】 - 76 -
9.7【虚函数】 - 78 -
9.8【静态构造函数与私有构造函数】 - 78 -
9.9【多态的概念】 - 82 -
9.10【索引器】 - 85 -
第10章:继承与接口 - 86 -
10.1【继承基础问题】 - 86 -
10.2【关于new】 - 91 -
10.3【this问题】 - 96 -
10.4【base问题】 - 99 -
10.5【抽象类】 - 101 -
10.6【接口】 - 108 -
10.7【其它】 - 111 -
第11章:委托,事件,泛型 - 117 -
11.1【委托】 - 117 -
11.2【事件】 - 127 -
11.3【泛型】 - 130 -
第二部分:数据结构和软件工程 - 132 -
第12章:数据结构 - 132 -
12.1【链表】 - 132 -
12.2【栈和堆】 - 134 -
12.3【树】 - 135 -
第13章:字符串 - 144 -
13.1【字符串基础】 - 144 -
13.2【StringBuilder】 - 145 -
13.3【正则表达式】 - 146 -
13.4【数组】 - 147 -
13.5【字符串其他问题】 - 148 -
第14章:排序 - 150 -
14.1【排序基础知识】 - 150 -
14.2【冒泡排序】 - 153 -
14.3【鸡尾酒排序】 - 156 -
14.4【选择排序】 - 157 -
14.5【插入排序】 - 159 -
14.6【希尔排序】 - 160 -
14.7【快速排序】 - 163 -
14.8【归并排序】 - 167 -
14.9【堆排序】 - 170 -
第15章:设计模式 - 172 -
15.1【基础模式】 - 173 -
15.2【结构模式】 - 181 -
15.3【Clone】 - 184 -
15.4【观察者模式】 - 187 -
15.5【UML】 - 189 -
15.6【软件工程】 - 192 -
第16章:软件测试 - 194 -
16.1【白盒测试】 - 195 -
16.2【性能测试】 - 200 -
16.3【关于游戏】 - 200 -
第三部分:Unix,Oracle,网络 - 202 -
第17章:操作系统面试例题 - 202 -
17.1【进程】 - 203 -
17.2【线程】 - 207 -
17.3【UNIX】 - 209 -
17.4【Windows】 - 212 -
第18章:数据库和SQL语言 - 213 -
18.1【数据库理论】 - 213 -
18.2【ORACLE基础】 - 215 -
18.3【SQL语言客观题】 - 217 -
第19章:计算机网络及分布式系统 - 222 -
19.1【网络结构】 - 222 -
19.2【TCP/IP】 - 223 -
19.3【网络安全】 - 227 -
19.4【网络其他】 - 228 -
第四部分:.NET扩展项目 - 230 -
第20章 Winform窗体与控件 - 231 -
20.1【窗体类】 - 231 -
20.2【控件类】 - 232 -
20.3【图形】 - 232 -
第21章 ADO数据库相关 - 233 -
21.1【ASP.NET基础】 - 234 -
21.2【ADO.NET体系结构】 - 235 -
21.3【数据绑定】 - 237 -
21.4【Datagrid】 - 239 -
21.5【Dataset】 - 240 -
第22章 .NET中Web设计 - 241 -
22.1【Session】 - 242 -
22.2【Cookie】 - 244 -
22.3【XML】 - 245 -
22.4【数据传递】 - 247 -
第23章ASP.NET应用技术 - 249 -
23.1【.NET 局域网】 - 250 -
23.2【.NET Remoting体系】 - 251 -
23.3【Webservice】 - 254 -
第24章 .NET性能与安全 - 255 -
24.1【内存管理】 - 255 -
24.2【垃圾管理】 - 256 -
24.3【.NET安全设置】 - 258 -
第五部分:综合面试题 - 258 -
第25章 英语面试 - 259 -
25.1【面试过程和技巧】 - 259 -
25.2【About job】(关于工作) - 260 -
25.3【About person】(关于个人) - 263 -
25.4【About future】(关于未来) - 266 -
第26章 电话面试 - 267 -
26.1【电话面试之前的准备工作】 - 267 -
26.2【电话面试交流常见问题】 - 268 -
第27章 智力测试 - 274 -
27.1【关于数字的智力问题】 - 274 -
27.2【关于推理的智力问题】 - 277 -
27.3【关于综合的智力问题】 - 280 -
27.4【关于群体面试】 - 281 -
第28章 逻辑测试 - 284 -
28.1【文字逻辑】 - 284 -
28.2【图形逻辑】 - 286 -
28.3【找规律】 - 288 -
28.4【关于表格】 - 290 -
附录 面试经历总结 - 298 -
本书样张如下:
5.5【其它】
面试例题1:编写一段代码,其功能是打印代码本身。(要完全使用程序代码生成一段和自己的代码一模一样的字符串)。[欧盟著名通讯公司N面试题,2008]
解析:一道很有趣的面试题,就好像要求一个魔术师,扯着头发把自己拔起来的感觉。本题在编写时要注意计算代码长度。
答案:用C#编写代码如下:(仅一行)
class P { static void Main() { string s = "class P{{static void Main(){{string s=;System.Console.WriteLine(s,s,(char)34);}}}}"; System.Console.WriteLine(s, s, (char)34); } }
6.1【const】
面试例题1:const 和 static readonly 区别是什么?
解析:
这个问题虽然很简单,但有时候也能困扰我们。const和static readonly的确很像,都在程序中只读,都是一旦初始化则都不再可以改写,都是属于语言的静态。并且在多数情况下可以混用。
两者区别是这样的,关于const
1.在编译期间解析的常量;
2.必须在声明就初始化;
3.既可用来修饰类中的成员,也可修饰函数体内的局部变量。
而关于static readonly
1.在运行期间解析的常量;
2.既可以在声明时初始化,也可以在构造器中初始化;
3.只可以用于修饰类中的成员
这里有几个例子:
static readonly MyClass myclass = new MyClass();
//必须使用static readonly,因为new需要在运行时确定
//而const只能必须在编译时就确定
static readonly A = B * 20;
static readonly B = 10;
//可以使用static readonly,显然可以在运行时确定语句
//也可以使用const// const A = B * 20;
// const B = 10;
//编译器会在编译时候,就把B编译为10,A编译为200,而不是在运行时再计算B * 202.
下面有一个项目,有一个MyInt的属性,定义如下:
public class MYClass
{
public const int MyInt = 5;
public static readonly String strStaticReadonly = "StaticReadonly";
}
另一个项目中引用该属性
public class AnotherClass
{
int I = MYClass.MyInt;
string kk = MYClass.strStaticReadonly;
}
编译运行程序, I = 5;kk = StaticReadonly。这是当然的。但是如果我们改变MYClass中的MyInt和strStaticReadonly的值:
public class MYClass
{
public const int MyInt = ; //这里改为6
public static readonly String strStaticReadonly = "changed";//这里改为changed
}
然后编译MYClass所在的项目,生成dll。再运行程序AnotherClass(只是运行,而不是编译后运行),发现I还是= 5,而不是6!,但是strStaticReadonly却变成了changed。为什么会这样?因为在AnotherClass中,I已经被定义为5而不是运行时再去取dll的值,所以说const是编译时就唯一确定了。
答案:C#拥有两种不同的常量:静态常量(compile-time constants)和动态常量(runtime constants)。它们有不同的特性,错误的使用不仅会损失效率,还可能造成错误。相比之下,静态常量在速度上会稍稍快一些,但是灵活性却比动态常量差很多。
//静态常量(隐式是静态的)
public const int compiletimeConstant = 1;
//动态常量
public static readonly runtimeConstant = 1;
静态常量在编译时会将其替换为所对应的值,也就是说下面这2句话通过编译器编译后产生的中间语言是一样的。
//通过编译后二者会被翻译成相同的中间语言
int myNum = compiletimeConstant;
int myNum = 1;
动态常量的值是在运行时获得的。编译器将其标为只读常量,而不是用常量的值代替。静态常量只能被声明为简单的数据类型(内建的int和浮点型)、枚举或字符串。下面的程序段是通不过编译的。你不能用new关键字初始化一个静态常量,即便是对一个值类型来说。
//这样是错误的
public const DateTime myDateTime = new DateTime(2006,9,1,0,0,0);
//这样是可以的
public static readonly DateTime myDateTime = new DateTime(2006,9,1,0,0,0);
只读数据也是常量的一种,它们不能在构造器初始化之后被修改。但是它同静态常量不同,它的值是在运行时才被指派的,因此就会获得更大的灵活性。动态常量可以是任意的数据类型。二者最大的差别在于:静态常量在编译时会将其换为对应的值,这就意味着对于不同的程序集来说,当你改变静态常量的时候需要将其重新编译,否则常量的值不会发生变化,可能引发潜在的问题,而动态常量就不会有这种情况。用const定义的常量(隐式是静态的),需要像访问静态成员那样去访问const定义的常量,而用对象的成员方式去访问会出编译错误。 声明的同时要设置常量值。从另一方面来说,如果你的确要声明一些从不改变且处处唯一的常量,例如钩子函数SetWindowsHookEx的idHook参数或序列化时的版本等,就应该使用静态常量。但是用到这样的常量的机会不多。一般来说我们应该使用灵活性更高的动态常量。
两者区别如下:
静态常量 动态常量
内存消耗 无 因为要保存常量 有消耗
初始化 很少的简单类型;不能new,必须在声明同时赋值 任意类型,可以在类构造函数中赋值
何时发挥作用 编译时进行替换 相当于类中的数据成员
11.2【事件】
面试例题1:写一个事件,公司饮水机没水时候,小王、小李或者公司其他同事给引水机加水?
解析:本题主要考校观察者模式,观察者模式中主要包括如下两类对象:
1. Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,饮水机就是一个监视对象,它包含的其他对象所感兴趣的内容,就是waterTankState字段,当这个字段的值为0的时候,会不断把数据发给监视它的对象。
2. Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer就是员工,它们采取的行动分别是Drink和FillWater。
在本题中,事情发生的顺序应该是这样的:
1. 员工告诉饮水机,它对它的容积比较感兴趣(注册)。
2. 饮水机知道后保留对员工的引用。
3. 员工到饮水机前进行饮水这一动作,当容积为0,通过引用,自动调用Fillwater()方法。
类似这样的例子是很多的,GOF对它进行了抽象,称为观察者模式:观察者模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。观察者模式是一种松耦合的设计模式。
答案: 详细代码如下:
// Observer pattern -- Structural example
using System;
//Delegate 加水委托
delegate void fillwaterDelegate();
//ConcreteWaterTank 创建水箱类
class ConcreteWaterTank
{
// Fields
private int subjectCubage; //当前容积
public event fillwaterDelegate fillwaterHandler; //建立加水事件
// Properties
public int waterTankCubage
{
get { return subjectCubage; }
set { subjectCubage = value; }
}
// Methods
public void Attach(fillwaterDelegate ud)
{
fillwaterHandler += ud;
}
public void Detach(fillwaterDelegate ud)
{
fillwaterHandler -= ud;
}
public void Notify()
{
if (fillwaterHandler != null) fillwaterHandler();
}
}
// "ConcreteEmployee" //建立员工类
class ConcreteEmployee
{
// Fields
private string employeeName; //员工姓名
private int observerCubage; //关注水箱状态
private ConcreteWaterTank subject;
// Constructors //建立构造函数
public ConcreteEmployee(ConcreteWaterTank subject,
string employeeName)
{
this.subject = subject;
this.employeeName = employeeName;
}
// Methods
public void fillWater()
{
if (subject.waterTankCubage == 0)
//关注水箱 如果水箱没水 则注水
{
Console.WriteLine("Employee go to waterTank and find the water is Null", employeeName);
subject.waterTankCubage = 10;
observerCubage = subject.waterTankCubage;
Console.WriteLine("Employee fill water to waterTank.Now waterTank's state is ", employeeName, observerCubage);
subject.waterTankCubage = subject.waterTankCubage - 1;
observerCubage = subject.waterTankCubage;
Console.WriteLine("After do that he drink, Now waterTank's state is ",employeeName, observerCubage);
}else
{
//否则 则饮水
subject.waterTankCubage = subject.waterTankCubage - 1;
observerCubage = subject.waterTankCubage;
Console.WriteLine("Employee go to waterTank, and he drink, Now waterTank's state is ",employeeName, observerCubage);
}
}
// Properties
public ConcreteWaterTank waterTank
{
get { return subject; }
set { subject = value; }
}
}
// "ConcreteEmployee" //其他观察者 他们仅是观察但不动作
class AnotherObserver
{
// Methods
public void Show()
{
Console.WriteLine("AnotherObserver got an Notification!");
}
}
public class Client
{
public static void Main(string[] args)
{
ConcreteWaterTank s = new ConcreteWaterTank ();
//建立水箱s
ConcreteEmployee o1 = new ConcreteEmployee(s, "ZhangSan");
ConcreteEmployee o2 = new ConcreteEmployee(s, "LiSi");
ConcreteEmployee o3 = new ConcreteEmployee(s, "WangEr");
ConcreteEmployee o4 = new ConcreteEmployee(s, "ZhaoLiu");
//建立员工对象 张三 李四 王二 赵六并绑定水箱s
AnotherObserver o5 = new AnotherObserver();
//建立普通观察者对象 o5
s.Attach(new fillwaterDelegate(o1.fillWater));
s.Attach(new fillwaterDelegate(o2.fillWater));
s.Attach(new fillwaterDelegate(o3.fillWater));
s.Attach(new fillwaterDelegate(o4.fillWater));
s.Attach(new fillwaterDelegate(o5.Show));
//绑定事件fillwaterHandler
s.waterTankCubage = 2;//水箱初始状态2升
s.Notify();//事件开始运行
Console.WriteLine("--------------------------");
s.Detach(new fillwaterDelegate(o1.fillWater));
//把o1也就是员工张三加水行为从事件中剥离
s.waterTankCubage = 1; //水箱初始状态1升
s.Notify();//事件开始运行
}
}
12.2【栈和堆】
面试例题1:编号为123456789的火车经过如下轨道从左边入口处移到右边出口处(每车都必须且只能进临时轨道M一次,且不能再回左边入口处) [中国台湾计算机硬件公司W面试题,2008.11]
-----------------------------------------------------
987654321
------------------- /-----------------------------
| |
| |
|M|
| |
|_|
按照从左向右的顺序,下面的结果不可能是______
A 123876549
B 321987654
C 321456798
D 987651234
解析:本题实际上考的是数据结构的栈。临时轨道M就是栈。
A 123挨个过去,45678入栈再出栈变成87654,9再过去;
B 123入栈再出栈变成321,456789入栈再出栈变成987654;
C 123入栈再出栈变成321,4567直接过去,89入栈再出栈变成98;
D 98765在前,则1234必须全部先进栈,98765过去后,剩下1234必须先回到左边,再通过才满足1234。但是题意要求不可再回到左边入口处,所以这个选项不可行。
答案:D
扩展知识:如果M只能容纳4列车。上面选项因该选哪个才可行?
16.2【性能测试】
面试例题1:在用户体验测试中,发现问题可能存在误测,误测包括两种:第1,问题被遗漏了;第2,不是问题却被认为是问题。我们的测试通常通过两种不同的测试方法来进行,他们依据完成不同的设计思路,但是有一些共同的:第1他们都能发现所有存在的问题;第2仍然会有百分之三的误测率;第3不会出现同一问题被对两个系统都误测的可能性。为了测试一个非常重要的系统,我们会把两个测试方法进行交叉测试,测试结果采取并集,我们可以这样推理:采用这种方法的时候是不会出现任何误测的情况。
以下哪项最恰当描述了上述推理?
A 上述推理是必然的,即如果前提为真,则结论一定真;
B 上述推理很强,但不是必然,即如果前提条件为真,则为结论提供很强的证明,但附加信息仍可削弱论证;
C 上述推理很弱,前提条件尽管与结论相关,但最多只为结论提供不充分证明;
D 推论不成立,因为他把某些必要的条件当作了充分的条件。
解析:因为从前提条件中只知道有两种误测,但并未说明两种误测能够在测试时就知道,因此当误测发生时,我们无法区分是哪种误测,因此即使使用两种测试方法进行交叉测试取并集,最多只能保证不被遗漏,但是不能解决不是问题却被认为是问题。
答案:D
第27章 智力测试
27.1【关于数字的智力问题】
面试例题3:1000瓶药水,其中至多有1瓶剧毒,现在给你10只小狗在24小时内通过小狗试药的方式找出哪瓶药有毒或者全部无毒(小狗服完药X小时后才会毒发。19<X<23)[中国著名互联网企业T面试题,2008年11月]
答案:按10进制方式给狗编号分别是1-10。按2进制方式给药水编号。按照药水第几位数字为1,给相应的狗服药。如下:
第1瓶 0000000001 第1位数字为1,给1号狗服药。
第2瓶 0000000010 第2位数字为1,给2号狗服药。
第3瓶 0000000011 第1、2位数字为1,给1、2号狗服药。
第4瓶 0000000100 第3位数字为1,给3号狗服药。
……
第99瓶 0001100011 第1、2、6、7位数字为1,给1、2、6、7号狗服药。
……
第455瓶 0111000111 第1、2、3、7、8、9位数字为1,给1、2、3、7、8、9号狗服药。
……
第1000瓶 1111101000 第4、6、7、8、9、10位数字为1,给4、6、7、8、9、10号狗服药。
最后看哪只狗毒发,则通过狗的编号得出药瓶号码。比如1、2、3、7、8、9号狗毒发,则455瓶(编号0111000111)为毒药。