1.谈谈你对java是解释执行这句话的理解
-
这句话不准确。java代码首先是通过javac命令编译成字节码,在运行时被解释器转为机器码。
-
但是常见的jvm,例如hotspot,都提供了JIT动态编译,能够在运行时将热点代码编译成机器码,这种情况下的代码就属于是编译执行,而不是解释执行。
-
还有一种新的编译方式,即AOT,直接将字节码编译为机器码
2.Exception 和 Error 有什么区别?
-
都继承了throwable接口,java中只有Throwable示例才可以被抛出或者是捕获。
-
Error是指,在正常情况下不大可能出现的情况,会导致程序处于非正常的不可恢复状态。例如OutOfMemeoryError。
-
Exception分为可检查异常和不可检查异常。可检查异常是在代码里必须显示的进行catch的异常,例如IOException等;不可检查异常就是所谓的运行时异常,例如nullPointException等。
-
需要注意的情况。不要捕获类似于Exception这样的通用异常,要对不同的异常进行特定处理;不要生吞异常,可以通过打日志等,展示异常。
-
try catch 代码快不要包含过多代码,因为会产生额外的性能开销,并且会影响jvm对代码的优化。
3.谈谈你对final,finally,finallize的理解
-
final可以用来修饰类,方法,变量。修饰类表示类不可被继承,修饰方法表示方法不可被重写,修饰变量表示变量是不可被修改的。
-
finally 是用来保证重点代码一定会被执行的机制,例如jdbc关闭数据库链接,unlock等操作
-
finallize 可以用来保证对象在被垃圾回收前完成特定资源的回收。
-
在java7中可以用try with resource 来省略掉 finally 关闭资源的代码
-
给对象声明final 只是表示对象的引用不会被修改,但是不能防止对象的内容被改变,例如list依然可以用add方法来给集合添加元素。一个有效的方法是,将集合对象声明为final,并且将集合中的每一属性也设置为private final,且不提供set方法。对于get方法可以用 copy on write的方式来实现。
-
在什么场景下finally 语句中的代码不会被执行,例如一段try catch finally 代码快中,在try环节抛出异常,进入到catch环节,并且在catch环节又抛出异常,那么finally 部分就不会被执行。或者在finally 代码快执行之前调用了 system.exit()方法。
4.强引用,软引用,弱引用,幻象引用的区别
-
强引用就是我们常见的最普通的引用,只要还有强引用指向的一个对象,垃圾回收器就不会回收这个对象
-
软引用,是一种相对强引用的弱化引用,还有当jvm内存不足的时候,也就是抛出OOM错误之前才会回收软引用对象,通常用作内存敏感的缓存
-
弱引用,不能使对象避免垃圾回收。当试图获取对象的时候,如果对象还在,就返回,如果对象不在,则重新进行实例化。同样可以用作缓存。
-
幻象引用,用来提供在finallize之后,做某种事情的机制。也可以用来监控对象的创建和销毁。
5.String、StringsBuffer、StringBuilder的区别
-
String 是final类,
-
StringBUffer本质是一个线程安全的字符序列,相关方法都加了synchronized关键字
-
StringsBuilder是一个线程不安全的字符序列,相对于StringBuffer来说,只是在相关的方法上去掉了synchronized关键字。
-
在java8 之后,字符串的拼接操作,会被编译为StringBuilder操作。可以通过反编译手段看。
-
最初的String 是用 char数组实现的,后来改为 byte数组。原因是拉丁语的字符只占一个字符位,而char占用两个字符位置。这样做可以使数据更加紧凑。
6.动态代理是基于什么实现的?
-
JDK的动态代理是基于接口的,需要对应的代理类有实现的接口,通过反射来实现。
-
Cglib是通过创建代理类的子类来实现对代理类的扩展。
-
动态代理的应用:监控,日志,事务,RPC框架的序列化和反序列化,诊断,限流,安全策略。
7.int 和 Integer
-
Integer会默认缓存 -128 到 127 之间的数据,通过Integer.valueOf(),会调用到缓存,并且可以通过参数 -XX:AutoBoxCacheMax=N 修改缓存的范围。 Boolean会缓存 true 和 false;Short 缓存范围也是 -128 到 127;Byte数值有限会全部缓存;Character 会缓存 ‘\u0000’到’\u007F’。
-
Integer是一个final类。
-
原始的线程安全类型应该是用 AtomicInteger ,AtomicBoolean等。
8.对比Vector、ArrayList、LinkedList有何区别?
-
Vector 内部以数组存储,随机访问性能较高,除了在尾部删除插入元素,性能会相对较差。方法实现全部加了synchronized 同步,是线程安全的。
-
ArrayList内部以数组存储,随机访问性能较高,除了在尾部删除插入元素,性能会相对较差。不是线程安全的。
-
LinkedList 继承了List 和Queen 但是存储形式是以Node的链表的形式存储的,并且是双向链表,每一个节点都保存有前一个和后一个节点的引用。同时也不是线程安全的。
9.TreeSet、HashSet、LinkedHashSet
-
TreeSet支持自然顺序访问,
-
HashSet 是利用哈希算法实现,如果哈希散列正常,增删改查等操作都可以达到常数时间
-
LinkedHashSet 是一个双向链表。
10.Hashtable、HashMap、TreeMap
-
HashTable扩展了Dictionary类,结构于HashMap明显不同,是线程安全的类,都加了synchronized
-
HashMap通常就是放入、访问或者删除,而对顺序没有特别要求,HashMap 在这种情况下基本是最好的选择。
-
LinkedHashMap 通常提供的是遍历顺序符合插入顺序,它的实现是维护一个双向链表。
-
对于 TreeMap,它的整体顺序是由键的顺序关系决定的,通过 Comparator 或 Comparable(自然顺序)来决定。
-
HashMap的存储是一个数组,通过hash算法将不同的值放在不同的索引位置上,然后如果两个索引值相同,则在同一个索引下,搞一个链表。
-
Java8在链表长度默认>64的时候,会改为红黑树的结构。
-
HashMap的resize方法,有两个功能,创建初始表格和扩容。