1. Exception和Error有什么区别
- 两者都继承了Throwable类
- Exception是可捕获的,开发者可尽量避免的。error是错误,可以中断程序的运行
- Exception 又分为可检测异常和非检测异常(运行时异常)。比如 IOException是checked异常,NPE、数组越界、ClassNotFoundException、
-
error 是程序运行中的异常,常见的比如内存溢出、NoClassDefError
简单的UML类图如下:
思考如何引导面试官?
- ClassNotFoundException & NoClassDefError 回答的时候说出这两个异常,引出这两个的对比。 ClassNotFoundException 的父类是反射异常,多出现于用了反射的地方,比如class.forName。NoClassDefError这个开发中遇到较多,通常是jar包冲突。(再思考如何解决jar冲突)
- 日常开发过程中,try catch 的使用,如何打印异常堆栈信息、 try with resource 、多个cause捕获
- 对应的项目中的是否使用了自定义异常,用来做什么
2. final、finally、finalize
- 三者除了张的像没有关联点
- final 可用于类(这个类不能被继承)、可作用变量、参数(不可被修改)、可作用于方法(不可被重载)
- finally 异常捕获中的语法,一般用于关闭资源。
- finalize 和垃圾回收相关,就是一个对象被虚拟机回收前需要执行的方法。这个问题较多,java9已废弃。
思考如何引导?
final 主要用于保证不可变性,因此多用于高并发,结合简历中的组件、以及项目经验描述,引导面试官问自己熟悉的项目。
3. 强引用、软引用、弱引用、幻象引用
java中的数据类型就是基本数据类型+引用数据类型。 引用和可达性分析息息相关。
- 强引用: 我们创建一个对象就是一个强引用。当jvm内存不足的时候,会抛出内存泄漏异常,也不会去回收强引用的对象。
- 软引用: 通过SoftReference创建。 当jvm内存不足的时候,会去回收软引用指向的对象。 软引用通常和引用队列(ReferenceQueue)一起使用,当jvm回收了软引用指向的对象,会把此对象加入到引用队列。 可以通过referenceQueue.poll()方法来判断软引用对象是否存活。
- 弱引用:通过weakReference创建。 弱引用指向的对象,被gc扫描到就会回收,不管此时内存是否不足。 弱引用也通常和referenceQueue一起使用。
软引用和弱引用通常应用于本地缓存的实现。
- 幻象引用。通过PhantomReference类来实现。无法通过幻象引用访问对象的任何属性或函数。幻象引用仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。
这个引用分析,和垃圾回收要联系到一起回答问题。
4. String、StringBuffer、StringBuilder
- String 字符串,是常量不可修改。 存储与常量池,java8之后存储在堆中。
- StringBuffer 用于组装字符串。 因为字符串是常量不可修改,当发生变化的时候会出现中间变量。StringBuffer内部是可变的char数组(java9 优化为byte数组),默认初始化为16。
- StringBuilder 功能同上,只是不是线程安全,append等操作去除了syn操作。
String 不可变属性,有很多好处,比如深拷贝不需要重新复制,并发不需要考虑并发读写问题。但是会出现很多重复变量。
重复变量的解决方式:
- 在创建字符串的时候 调用 String.intern(),会先查看常量池中是否存在,如果不存在重新生成并放回常量池。
- 8.0 gc1 可以做字符串排查,开启参数 -XX:+UseStringDeduplication
5. Vector、ArrayList、LinkedList 有何区别?
- Vector 、arrayList 内部时数组,linkedList内部是双向链表。
- Vector、arrayList ,vector 是线程安全。 linkedList 和 arrayList 都不是线程安全。
- vector 、arrayList 数组容量有限,达到上限vector数100%扩容,arrayList 是50%扩容。
5. Hashtable、HashMap、TreeMap 有什么不同
- hashtable 线程安全,key值不能为null值
- hashmap 线程不安全,key可以为null。
数据结构
数组+链表,链表长度大于8,会用红黑树保存。
初始容量
容量因子0.75 - treemap 线程不安全,有序,基于红黑树实现。 顺序是自然顺序,根据compator的值来计算,与此对应LinkedHashMap 有序,且顺序和插入顺序一致。
linkedHashMap 通常可以用来实现资源释放操作。
public static void main(String[] args) {
LinkedHashMap<String, String> hashMap = new LinkedHashMap<String, String>() {
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > 3;
}
};
}
6. ConcurrentHashMap & HashMap
- concurrentHashMap 并发安全。
- jdk7 中,concurrentHashMap中新增了分段的概念,每个段中是数组+链表的形式。
- concurrentHashMap 采用分离锁,粒度是在每一段中, key 采用不可变量,value使用volatile 字段保证可见性。
- size值计算 是采用重试机制,重试两次,如果两次值一样就取当前值,不一样则锁定所有的分段计算。
- 扩容和hashMap类似,只不过是按段扩容。
java8 发生很大变化,没有了分段的概念, 因此采用了延迟加载策略。加锁是靠cas操作。 size值采用了CounterCell。
7. java IO 和io多路复用
java io分为三种
- 同步阻塞,常见的流模型。 字节流,字符流,带缓冲区的字节流、文件流,网络流(socket、URL)。
- NIO 采用了channel (文件描述符,更底层)、selector、buffer 实现了 多路复用的 同步非阻塞模型。
- NIO2 或者叫AIO,异步非阻塞,采用的是事件回调机制。
NIO瓶颈: NIO selctor是一个线程,如果一个业务逻辑在处理过程中,延迟,那么会影响后续的已就绪的IO的处理。
8. java文件拷贝方式
java IO 读取,会有用户态和内核态的转换。
NIO读取,零拷贝方式,直接在内核态中完成。