记阿里第一次面试

     
 好像是上个星期阿里给我打的电话,是的,电话面试,我是内推提交的简历。第一次是下午2点,第二次是下午4点,我都在睡觉,我觉得下午2点到4点是最好的睡觉时间,所以一般下午没课,我都是2点到4点睡 午觉。第三次打电话大概是下午7点多了,这个时候长沙的天已经完全黑了。

     
室友在吃鸡,有点吵,于是我就跑到三楼到四楼的楼梯间去了。首先是自我介绍,这个就不说了,当时有点小紧张,没有组织好语言,就简单地把自己的学校、自己所学专业、老家哪的、在学校参加过什么部门、做过哪些项目简单地讲了一下,但感觉确实没有组织好语言。然后就是面试官的正式提问了,首先当然就是问项目的事了,要我简单地把项目介绍一下,我就把项目从平台性、有哪些功能、大概用了什么技术和框架说了下,听面试官司的语气好像有点不满意,确实,我做的那几个项目已经有点久了,有点不记得了。我主要说了下用了Spring框架,面试官就问我SpringMVC的机制。我的回答是SpringMVC是基本DispatcherServlet的,也就是在Tomcat的架构下,配置的DispatcherServlet接收到Http请求,然后根据相关的路由,也就是一些HandlerMapping,通过这个HandlerMapping把请求映射到相应的Controller,然后就把请求参数封装到相应的处理方法的参数中,然后就在Controller的方法里执行业务逻辑,业务逻辑处理完后就返回一个ModelAndView对象,把这个对象交给视图解析器,也就是ViewResolver解析,最后把结果返回给Servlet,给出Http请求的响应体。可能面试官对这个过程也不太了解,所以他也没有继续询问细节了,还好没问,其实我也就知道这么多了。最近正在看《Spring技术内幕》这本书,还只看到了Ioc的实现那里,后面的AOP和SpringMVC的实现细节还不是很了解。

   
 然后就问了用SpringMVC的好处,这个问题比较开放,我当时也懒得组织语言了,就简单地把自己认为SpringMVC比较好的方面说了下,比如说可以解耦呀,比如可以和Spring无缝对接,让Spring窗口管理对象,方便测试啥的。面试官对我的这个回答也好像不是很满意,但我也没办法了,我就随口说说的。

   
 然后再问了IoC和AOP的实现原理,我就回答IoC就是DI,用依赖注入管理对象之间的关系,比如说一个类中有另一个类的对象当属性,那么这两个类就有了一定的关系,IoC就可以管理这种关系,通过配置的方式来让一个对象注入到另一个对象中,而不是在一个对象中new另一个对象,如果直接new的话,就必须知道实现类是什么,而面向对象编程提倡面向接口编程,也就是要尽量面向抽象,而不是面向实现,在一个类中的属性或参数最好都用接口,而运行时才注入相应的实现类对象,Spring IoC就可以通过配置的方式来管理这些关系。这个就没什么好说的了。问我AOP是什么,怎么实现的,我就是AOP就是面向切面编程,也就是可以在一个方法执行前、执行后、或者抛出异常时能够做相应的处理,在应用中把这些有相同前置、后置或者异常处理的部分提取出来,统一管理就是切面了。实现方式就是设计模式中的代理模式,也就是要有一个调用对象的代理对象,在这个代码对象中持有被代理对象,当调用被代理对象的方法时,实际是调用的代理对象的相同方法,在这个方法中再调用被代理对象的方法,这时就可以在调用被代理方法之前、之后或者抛出异常时做一些处理。这个回答他好像很满意的样子,他就再追问具体是怎样实现的,我就说Spring有三种实现方式,分别是JDK自带的动态代理、AspectJ框架,还有一种叫什么名字来着的,他提醒我是cglib,我说“是是是,就是cglib”,场面一度很尴尬,我连这个居然都忘了,当时我脸都快红了。然后他继续追问我cglib的实现机制是什么,我说是字节码技术,也就是动态生成了字节码,这种生成的字节码并不是储存到class文件中,而是直接存放在内存中,JVM通过类加载器去加载这些字节码数据,在内存中生成代理类的类信息。这时他好像很高兴的样子,应该是对我居然还了解这么低层的原理比较满意吧。继续问我对类加载机制了不了解,我说还比较了解。幸好寒假过年回家把《深入理解Java虚拟机》这本书看了两遍,对类加载过程有了大概的了解。我解释道,类加载机制就是JVM把字节码解析成相应的类信息储存在内存中,这些字节码可能在class文件中,也可能是一些网络数据,但不管怎么说,都是一个字节码数据流,类加载器会把这个字节码流的数据加载到内存中,然后进行解析,把解析出的类信息,比如说类有哪些属性,有哪些方法什么的,这些信息储存是方法区,然后生成一个Class对象,这个Class对象就是访问这些类信息的入口。然后他问我类加载有哪几个阶段,这时我有点方了,我记得《深入理解Java虚拟机》里确实是讲过这个的,但我当时记不太清楚了,我说简单地说了下,应该有加载过程、解析、初始化过程、使用过程和卸载过程吧,然后他帮我补充了验证过程和准备过程,最终完整的过程应该是加载、验证、准备、解析、初始化、使用、卸载。再此,不得不佩服阿里的技术大佬们,工作这么久了,这些小知识点居然还记得这么清楚,我想那些读研的仁兄们应该从未听说过java还有类加载机制吧,不过,术业有专攻嘛,读研的同学们专心于学术和写论文,这些在实际项目开发中的概念和理论了解得比较少也很正常。然后让我简单地描述一下类加载的过程,我就说把字节码数据先加载到内存,然后JVM就开始解析这些数据,把解析的类信息储存到方法区中,然后在初始化阶段就初始化一些静态变量和一些静态代码块的,在这个类加载的过程中用的一个什么机制来着的,就是类加载器形成一个树状结构。他提醒我说是双亲委派模型,再问我为什么叫双亲委派模型,我正准备说这个,就说java类加载器有四种,分别是Bootstrap ClassLoader,是加载jdk下的lib目录中的jar文件中的class类的,然后是扩展类加载器,是加载lib目录下的一个扩展子目录中的jar文件中的class类的,然后是Application ClassLoader类加载器,是加载工作路径中的类的,比如说在工程中自己写的类或者添加的第三方jar包中的类。最后一种就是自定义的类加载器。这些类加载器是有父子关系的,比如说Bootstrap ClassLoader就没有父加载器,而扩展类加载器的父加载器就是Bootstrap ClassLoader,应用类加载器的父加载器是扩展器加载器,然后自定义的类加载器的父加载器是应用类加载器,这样就形成了一个树状结构。当一个类加载器在加载一个类时,会先用父加载器加载这个类,如果父类加载器也不能加载,就让父类加载器的父类加载器加载,这样一直到Bootstrap ClassLoader加载,就是先把加载任务委派给父类加载器加载,最后都加载不了后再自己试着加载,我说这就是我理解的为什么叫双亲委派模型。他好像比较满意,没有纠错,也没有再深问下去。再此,应该要说一句,少年人,一定要多多看书呀,可以说,这次面试,我靠《深入理解Java虚拟机》这本书就吹了半个多小时。


   然后他继续问我对多线程和同步了不了解,我就回答,由于我学过两年的Android编程,Android编程对线程要求比较高,所以我对多线程编程还算比较了解,然后他就说Andoroid中在非UI线程中更新UI会抛出异常,问我会抛出什么异常,这个我就不清楚了,我也只知道如果直接在自己开的线程中操作UI的话,APP会直接崩掉的,我就说会抛出不能在非UI线程中更新UI组件的异常,显然他是不满意的,但他肯定知道我也不知道是什么异常,所以就放过我了。后来我上网查了一下,这个异常是
CalledFromWrongThreadException。然后问我Android中在线程中更新UI有哪些方法,我就说常见的方法有四种,分别是使用Activity的runOnUIThread,在这个方法中传入一个Runnable接口的对象,在Runnable的run方法中就可以更新UI。第二种是使用Handler类,在线程中构造一个Message对象,把要传递的参数添加到Message的参数中去,然后用Handler对象发送这个Message消息对象,这样就可以在Handler的handleMessage方法中接收到这个Message消息对象了,从这个消息对象中取出相应的参数,根据这些参数就可以相应地更新UI了,然后第三种方法是用一个任务类,我当时没有想起具体叫什么名字了,就说好像叫AsycTask吧,里面有个后台执行方法,我们可以在这个后台方法中执行相应的多线程操作,然后把执行的结果数据通过一个方法发送出去,然后另外一个前台方法就会被调用,参数就是我们在后台执行中发送的数据,通过这些数据,也可以相应地更新UI,第四种方法我当时没有想出来,我说第四种方法我忘了。他也没有提醒我,可能是他也不知道是什么了吧。再此说一下,是View的post方法,传入一个Runnable对象进去,根Activity的runOnUIThread方法一样。接着他问我线程同步了解吗,我说还比较了解,Java线程同步主要有两种方法,一种就是传统的用synchronous关键词创建同步块或者同步方法,用一个对象锁把这个块或者方法锁住,持有相应锁的线程只有一个线程能够进入这个块或方法,其他线程只能等待这个线程执行完后才能进入。第二种方法就是基于Lock接口的同步方法。感觉他应该是觉得我对Java基于掌握得还不错,就不想在Java基本上再浪费时间了,就没有再继续问Java相关的了。

       
再问我关于数据库的,问我数据库事务,我说是ACID,是原子性,一致性,隔离性,还有一种什么来着,他提醒我说是持久性。哎,居然这都忘记了,我可是数据库课考了90多分的男人,还不到一年就全忘了,在此,感觉好对不起讲课让人想睡觉的谭老师,老师还是讲得蛮认真的,不过,他纯粹地讲课,真好太催眠了。然后问我数据库查询优化有哪些方法,我首先就想起了建立索引,然后他问我如果让我来实现索引,应该用什么数据结构,我说应该是用树结构吧,他说mysql低层的数据结构就是用的树,我说对对对,就是用的B+树,然后他问我B+树是什么,我说我也不太了解,就是知道B+树是一种特殊的树,所有的叶节点都在最下面那一层,然后储存的数据都在叶子节点中,非叶子节点只储存了索引路径。然后我就答不上来了,他应该也知道,就没有再追问了。然后他说还有哪些方法可以优化sql吗,我说应该还可以把比较具体的条件放到比较前面,这样有得于索引,还有就是在联表查询时可以先查询数据量比较小的,再链到比较大的表,现在才想到,这么说完全是扯淡。他问我知不知道explain,我说不知道,然后他就跟我解释explain可以查看到sql语句执行的细节,比如说用到了哪些中间数据,哪些键,哪些引用或者索引,通过这些细节,就可以做相应的sql优化。我当时就懵了,我还真是第一次听到sql中还有explain这个词。只想说一句话,少年人,还是得多看书。

     
然后他就没再问我技术了,就问我一些关于考研的事、学习的事,最近在读什么书没有,我就说在读一本阿里的高级工程师写的《大型网站系统与Java中间件实践》的书,这本书里讲了网站如何从一个小网站演进成一个大网站,会遇到哪些常见的问题,并给出了一些解决方案,在这本书里我收获还是挺大的。然后我说还看了《深入理解Java虚拟机》和《Java并发编程的艺术》,然后又讲了一些杂七杂八的事。

   
 面了大概一个小时左右吧,最后他说我对基本掌握得比较好,让我等待后面的面试通知。但我从他总体过程的语气来看,他对我貌似并不怎么满意,感觉自己悬了。哎,挂了就挂了呗,自己确实没有准备好,就寒假看了下《深入理解Java虚拟机》和那个Java中间件的书,然后在同学都回家过年了自己一个人在寝室待了十几天,看了些数据结构和算法的东西,数据库相关的东西完全没复习,挂了就挂了吧,也不怨他人,第三次说那句话,少年人,还是得多看书。最后听我们班其他面阿里的同学说,面他们的时候,整个过程完全是蒙的,问些基础完全答不上来,非常尴尬。我又一想我,除了Java基础还算拿得出手,其他东西,也就那样,估计是凉了。哎。