记我的一次面试经历, 感慨万千
好俗的博客题目,和小学作文差不多。
窃以为自己C#的水平已经达到了“熟练”的程度,毕竟怎么也有10W以上的开发经验了。可是因为各大公司从来都不面试C#,所以这半年我一直在复习C++,很久没有看C#的知识了。
那天中午因为着急,我午饭也没有吃,就直接打车去了某著名互联网公司。前台签到,等待一面。
一面是个挺帅气的年轻面试官,看了我的简历,对我做的项目挺感兴趣,我给他详细介绍了框架,UI,插件和类库的设计思路。他频频点头,说道“我们公司用的主要使用JAVA开发后台,不过我以前也做过C#,看你的开发经验比同龄应届生高出一大截,那我们就不妨讨论几个C#的基础问题吧。我就不拿JAVA和C++来面你了”。
饿的有点头晕的楼主一听要面C#,顿时开心的不得了。心想,“总算遇到懂行的人了,看来没白来。”
1. 哈希表的实现方法?
我一听,愣了一下,说道,哈希表主要是通过key-value对的形式存储关联信息的,通过索引器的方式通过key快速检索value. 而它们两的映射关系需要通过GetHashCode方法实现,String主要是通过字符串的操作(具体操作的那个名字我忘了),其他类可以通过重写该函数的形式实现,或者采用其默认实现(默认实现是怎样的?我也忘了)。
面试官刚听到这里,打断了我的话头,说你说的不完整,我们换个话题。(呜呜)
2. C#的String是值类型还是引用类型?
想当年,这个问题是难不倒我的,可是在面试那种环境下,脑袋被驴踢了。想着string的很多特性,直接脱口说“是值类型!” 面试官问道,它是类么?我说,是啊,实现了ICompare接口啊。“那你刚才不是说,所有的对象不都是引用类型吗?” 我顿时无语了,默默的说道“是引用类型”。
“再考考你,我们知道string是唯一的,只要你对它做任何操作,出现的新string和以前的完全是两个变量,那为什么这样处理?”
这个常识我知道,拼接字符串的性能是很差的,所以我们才使用StringBuilder。它的底层肯定是char数组,可为什么框架采用了以上的处理策略?脑子里全是准备面试时写的各种C++的字符串操作,百思不得其解。面试官看了我的囧样,又换了一个问题。
(回来后才一拍脑门,常量字符串区!所有生成的字符串在内存中仅会保留一份副本,为的当然是节省空间啊!)
3.GC的原理?
垃圾回收器?以前在讲原理的书上看过,我就侃侃而谈,GC主要按照代数工作,共分为三代,0代,1代,2代。0代一般是局部变量等容易被回收的。若在一次回收周期中没有被回收,则该变量代数+1。 另外,有一个引用计数的问题。每当B引用了A,A的引用计数就+1. 销毁了B, A引用计数就-1. 当某个变量引用计数值为0时,就该被回收了。 不过我不知道,当一个对象在外部被订阅了事件处理函数,GC是怎么处理的。
面试官笑了笑,引用计数?VB6和以前的一些语言,都是用引用计数的,不过现代的C#和JAVA都不用引用计数而采用“代数”的方法了。那你说,为什么不使用引用计数了?
引用计数,我想起了以前超难解决的子图分割问题。我画了一幅图: A,B,C相互连接。说道,三个变量都没有用了,可是它们互相耦合,引用计数都不为0,GC无法回收,所以这种方式不好。所以需要采用子图分割的方法。
面试官说,引用计数只是个数,它可没有保存图的结构,你怎么子图分割?
我说,是啊,是个很难的问题,还是“代数”方便一些。
面试官笑了笑,我们再换个话题。
4. 值类型一定在栈上吗?
我说道,我写过一篇博客,说的就是这个问题。C#中,值类型的局部变量都在栈上。
“所有的情况都在栈上么?”
当然不是,比如在一个类中定义的值类型成员,它处在堆上。
还有其他的情况么?
我想啊想,怎么也没有想出来。面试官说,想想lamda表达式。
我一拍脑袋,闭包!但我和面试官说,虽然闭包做了一个局部变量的拷贝,它存储在堆上。但我认为它们并不是一样的变量,而且闭包还有陷阱。总之这个事情比较麻烦。
面试官笑了笑,说,你回去再查一下吧。
5.线程安全怎么处理?
线程安全?我脑子里出现了一堆与“锁,互斥,线程同步”的一堆词汇。我说道,线程安全主要是为了保护共享变量,保证“原子性”。然后说道,我曾经在用log4net日志系统输出UI的调试信息时,常常因为多个线程同时输出而产生锁死问题,于是查了不少资料,采用了Monitor类,使用了如下代码:
private readonly object lockobj = new object(); public void Info(object message) { bool lockTaken = false; Monitor.TryEnter(this.lockobj, 300, ref lockTaken); if (lockTaken) { try { this.thisXLog.Info(message); } finally { Monitor.Exit(this.lockobj); } } else { return; } }
面试官说,还有吗? 我说,我通常会使用线程安全的集合,比如.NET 4.5提供的一组线程安全集合,就不用做同步了。 面试官还是笑了笑。
6.C# 5.0有了async和await关键字,那异步的原理是什么?
以前看过某大神async和await异步的使用介绍,还在开发WP8时,大量使用了异步模式解决数据传输卡死UI的问题。以前用非异步开发WCF时,常常采用大量挂接事件的方式来“模拟异步”。但是代码丑陋,而且容易出错。
可是,真要问起原理,我还真没想过,”难道是类似消息队列那样的机制?“
面试官笑了笑,你也回去查一下吧。
聊到这里,我的脑袋上已经沁出了一些汗珠,一点饿的感觉都没有了。面试官说,看你用博客园,看看你的博客吧。我打开了博客,让他扫了两眼,他说,“我以前也玩博客园,最好的时候是第37名,当然现在两年多没玩了。”当时我就惊了。遇到大神了啊。
他接着说,“你的开发水平确实比同龄人强,可是对应届生来说,考察占50%比例的是基础知识,你说你对C#熟悉,可是我考你的这几个问题,你一个都没有完整的答上来,只是知其然不知所以然。我还没问你JAVA呢。这方面一定要注意啊,不过,我还是会让你通过面试的。”
我脸上红一块白一块的,一直在点头。”没错没错,只是最近一直在复习C++,C#太久没看,两年前看的东西现在很多都忘记了“。
他又说,”基础知识,在开发的时候好像感觉不出特别大的作用,可是在调试的时候,这就非常看功夫了。常常半夜起来,服务器负载超高,无法登陆,可是那时候又没人访问,怎么去查错?这种情况下,就要看你的基础知识了“。
我说,非常正确,我当时就因为做嵌入式开发时一个非常底层的问题卡了我半年,如果我基础知识和经验牢靠,可能就不会出现这样的错误了。
他笑着说,你还有什么问题么? 我说,”今天遇到大神了,我还需要继续努力。“后面的二面三面,且按下在此不表,至于以上的问题,我就不给出答案了,大家自己查阅吧。大家可以顺便猜下我拿到这家公司的offer没。
等我回到学校,我仔细看了他的博客,横刀天笑的碎碎念,顿时就吓尿了。果然是博客园前50的气质和实力:
该大神横跨.NET,JAVA和函数式编程,对设计模式,底层知识,算法和业务逻辑都有充分的见解,他问我的很多问题都来自于自己的博文。而且是能出”系列“的。而我呢?发的基本都是没有营养的牢骚贴和介绍帖,水了一逼。也许我唯一能值得说说的,就是好像我比他年轻,06年他开始上班写博客的时候,我才上高中呢。
好好反思自己,读书的时候喜欢跳读,平时遇到问题才去网上查,很少有系统的读书,也少有做笔记的时候。很多两三年前看的知识点,现在都只留下个影子。给人说上两三句就没有了。这还不如那些没搞过开发,却看了不少书的同学呢。
自认为自己搞的很宽,什么都有涉及。可是什么都不深刻,论WPF,我比不过Mgen, 论对语言的理解,我和这位MSRA的大神λ-calculus in CnBlogs比差了十万八千里(最近一直在反复的看他的博客,因为一遍根本看不懂)。当然还有我大四时认识的在高中就每天上课看C#的大神Loning's home(他还比我低一届)。 自认为懂机器学习和数据挖掘, 别人问我的问题稍微深一点就直接跪掉。 当然还有无数的大神没有写上来。 看他们的文章,每一个字都透出那种聪明和能力。而自己开始正经写代码已经是大三的时候了,在通信领域搞计算机,没有同道之人和大环境。和科班出身的同学相比,差距甚远啊。
以后每天努力学习,看大神的博客。还有横刀天笑大哥,谢谢你的提醒。
真是啥都不说了。干活吧。
作者:热情的沙漠
出处:http://www.cnblogs.com/buptzym/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。