思考
第一次面试,心态不足,准备不够,导致有些问题并没有达到面试官期待的结果,面完之后一直在思考面试中的问题,在此写下这篇博文;
面试总结
前一段时间,正好由于工作室学长在阿里巴巴工作有内推名额,所以将简历制作好之后投递过去就有了这次电面的经历
这是我真正意义上的第一次面试(Java研发工程师),紧张是难免的(但是貌似我是太紧张了,导致一些问题我没有很好的去发挥),所以正常的被刷;
面了1个小时10分钟,通过这次面试,对我个人而言收获颇多:
- 第一 Java基础,但是不是说你会应用就行,像大公司它考虑的就是你对这些基础的理解程度,概念是否清晰;
- 第二 临场应变能力,比如面试官问你一个具体的问题,让你去解决,注意这个问题不会很难但是都有几种解决思路;
- 第三 表达,能准确精简的表达你的解决问题思路,最忌讳的就是重复你的思路,自己都不知道自己在表达什么,如果不会就直接说不会,不要不懂装懂;
*** 不过阿里的面试官很nice! ***
面试细节
自我介绍
面试官晚上打电话过来,惊讶我一下,叫我准备2分钟开始自我介绍(自我介绍最好在之前准备在脑中有一个基本的框架,必须要说的有条理性,不能东一句西一句),我由于部分原因没考虑到这点准备不足导致自我介绍说的不够好;
Java基础
自我介绍完之后,开始聊Java,首先问Java中最擅长的是哪一部分(比如IO,网络,集合,线程,反射等);
开始聊的时候我提到了线程和面向对象:
然后问我线程 问启动线程的两种方式:
- 1.实现Runnable接口实现run方法
- 2.继承Thread类重写run方法
之后就产生一个简单的对比:这两种方式的区别是什么?
我回答:由于Java是单继承,实现Runnable接口方式更有利于扩展,还可以继承其他类;而继承Thread类则太封闭;
面试官说并没有回答其本质区别,之后引导我说出:区别就是实现Runnable接口的类不是一个线程,继承Thread类是一个线程;
由此来讲我的理解是偏向于应用的区别,但是面试官所讲的就是本质区别
然后这次面试的最严重问题来了:2.线程的本质是什么?
我回答:线程的本质是原子性,可见性
3.原子性和可见性如何理解(以一个两个线程共享一个HashMap对象场景来通过原子性和可见性证明其是否是线程安全)?
- 原子性:多个线程共享一个资源,一个线程对资源进行操作,其状态能够立即被其他线程可见;之后我发现我讲的貌似是可见性; 由于太紧张,之后卡在这个问题上,面完之后我再仔细思考如果我重新回答这个问题我会这样回答:
- 原子性:一个线程对HashMap进行读或写操作,操作要么成功,要么不成功这就是原子性,再举几个例子:a=1与 a++ a=1是原子操作,而a++则是非原子操作;
再比如MVC中的controller(接收视图层传递过来的请求,根据请求调用业务代码,要么操作成功返回Model或者操作失败返回错误信息等),再比如Http协议,Http协议是无状态的;
- 可见性:一个线程对HashMap进行写操作,改变了HashMap的状态,但是这个状态能够立即被其他线程所得知;
- 举个例子:如果一个线程对HashMap进行写操作hashMap.put(“test”,”test1”);正好其他线程从HashMap中取数据hashMap.get(“test”)取到的却是null;
可见性导致的一个线程安全问题,对于这个问题可以使用synchronized,voliate关键字保证其可见性;也可以通过创建Lock lock = new ReentrantLock()锁对象进行加锁和解锁操作来保证其可见性;
因为在这个问题上我提到了单例,面试官就单例来问创建单例的几种方式?如何保证单例是线程安全?
单例分为:
- 1.饿汉式单例
- 2.饱汉式单例
- 3.枚举实现单例
饿汉式单例一来就实例化类对象,饱汉式单例就是声明类对象引用,在提供给外部的接口方法中判断引用是否为null,如果为null则实例化类对象;
- 饿汉式单例由于是类加载就实例化类对象,所以不存在线程安全问题;
- 饱汉存在线程安全问题,可以通过加synchronized同步块保证线程安全;
- 饱汉与饿汉通过序列化还是可以获取对象实例(需重写readResolve方法做唯一处理),但是利用枚举实现单例就不存在这个问题,是真正意义上的单例
通过创建锁对象,通过try-finally块加锁和解锁操作保证其线程安全(由于太紧张我并没有回答这些,犯了一个低级错误,我直接说将类对象引用声明为final);
4.线程谈完之后,问我还有哪一部分比较擅长?(面试官说线程是Java里高级部分,一般面试高级工程师才会提到线程)我就选了集合来讲,首先问我集合中最熟悉的是?
ArrayList
5.ArrayList与LinkedList的区别
实现的数据结构不同
ArrayList采用的是数组,LinkedList采用的是双链表(由于很久没看LinkedList源码,有点忘记但是记得LinkedList中实现的一个迭代器中有previou和next方法我想就是双链表,有点取巧)
如果对查询效率有要求的话使用ArrayList,如果对插入,删除,修改效率有要求的话使用LinkedList,具体为什么请看看线性表与链表的区别对比;
6.之后问到Map,提到一个实际应用,利用HashMap利用LRU算法实现缓存?
如果HashMap初始有一个100的数量级,当你进行put操作,Map中已经有100个cache,需要调用LRU清除策略;
在添加cache时,保存一个当前时间戳,清除就只需清除时间戳最久的那个cache;
7.然后谈到面向对象,面向对象的几大特性?
封装,继承,多态,抽象
8.封装,抽象的本质?
我回答的是封装,抽象的具体应用(其实是白话),但是并没有很好的总结;所以精简总结表达也是十分重要的;
面试官的理解:被封装的方法,类,属性就是保证其不可变 抽象就是其所有东西都是可变的
9.之后问我SQL优化?
我就据MySql的查询缓存,PreparedStatement,*与指定列,插入语句的优化等(但是表达的不是很好);
10.最后问我索引是怎样实现的?
B树
11.问我B树的特点?
面完结束后就知道自己许多缺点;
通过这次面试收获蛮多!!!也算给自己敲了一次警钟;