java必问面试题(一)

1.list和set的区别是什么

我的解答:list是允许重复的有序集合;set是不允许重复的无序集合。
大佬们的解答(主要是实验室和评论区各位大神的理解):上面的一句可以看做表面上的两个主要区别。除此之外,还有以下几个区别:
1.接口实现。list的一般实现有ArrayList,LinkList,Vector。set的一般实现为HashSet,TreeSet,LinkHashSet。
2.set之所以能保持元素不重复,是因为增加元素时,会调用equals方法进行比较,如果相同的话,将不会添加并返回布尔值false。

2.了解CMS嘛,CMS的过程是怎么样的,哪些步骤需要用户线程停顿

我的解答:了解一些。CMS主要关注的是回收停顿时间,比较适用于用户交互频繁的系统,提高用户的体验。CMS的运行过程包括四个步骤:
1.初始标记
只标记于GC root能关联到的对象,速度快。
2.并发标记
跟踪GC root,对堆中对象进行可达性分析,找出存活的对象。这个过程可以和用户线程一起并发执行。
3.重新标记
为了修正并发标记的过程中,用户同时运行导致的部分对象的标记状态会改变。
4.并发清除
以上的过程中,初始标记和重新标记需要stop the world。

2.1 CMS的实现算法为什么是标记-清除,而不使用其他的算法,比如标记-整理算法

我的回答:CMS过程的最后一个步骤是并发清除,这个步骤是允许用户的线程一起并发执行的。如果是其他的算法,比如标记-整理算法,那么CMS这种全局垃圾回收的方式,最后一个整理的步骤需要stop the world,因此停顿时间变长。而CMS垃圾收集器关注的就是最短回收停顿时间,因此标记-清除更合适。

2.2 G1垃圾收集器同样关注降低停顿时间,那为什么G1垃圾回收器的算法实现采用标记-整理。

我的回答:G1垃圾收集器和其他的垃圾收集器不同,将java堆分为多个大小相同的Region。G1垃圾收集器可预测的停顿的特点,根据用户要求的停顿时间,每次回收优先回收价值大的Region,避免了全区域垃圾收集,回收时间短,效率高。因此在整理的阶段,停顿的时间会很短,同时又避免了标记-清除算法造成的内存碎片的问题。

2.3 G1和CMS的区别是什么

我的回答:
1.算法实现不一样。CMS只能回收老年代垃圾,算法实现是标记-清除。G1是堆全区域的垃圾收集器,回收新生代垃圾时复制算法实现,回收老年代垃圾算法实现是标记-整理。
2.G1在运作期间不会产生空间碎片,而CMS会产生。这是由于算法实现的不同导致的。标记清除算法在清除“死亡的对象”后,没有进行整理,导致内存空间支离破碎,没有足够大的连续内存,这可能导致频繁的Full GC。
3.G1的堆内存布局和CMS不同。G1将堆内存划分为多个大小相同的Region,新生带和老年代不再是物理隔离。
4.G1降低停损时间性能比CMS更优秀。G1可预测停顿,可以根据用户要求的停顿时间,寻找优先回收价值大的Region,避免了全区域垃圾的回收,效率更高。

3.为什么hashMap是线程不安全的?

我的回答:多线程的情况下,不加锁或者不进行无锁处理的话,那么很可能发生数据不一致,比如线程一在修改数据的过程中,线程2也执行修改操作,假设线程2先完成,那么当线程1完成时,直接线程2的操作进行了覆盖,会产生丢失修改。在JDK1.7中,在扩容时,因为转换时头插法会使链表倒置,两个线程同时执行扩容操作,那么可能产生死循环的不安全的问题。在JDK1.8中,使用尾插法,同时也不需要重新计算rehash了,不会产生死循环。

3.1 hashMap在1.7和1.8有什么区别和优化

1.底层数据结构不同:JDK1.7是数组+链表;JDK1.8是数组+链表+红黑树。1.8中当链表的长度大于8就转换为红黑树,因此遍历的时间复杂度从O(N)变成了O(logN),因此效率提高了。
2. JDK1.7 put数据时采用头插法;1.8采用尾插法。头插法多线程参与扩容时,链表逆序容易产生环形链表,在遍历时会死循环。尾插法避免了逆序和死循环。
3. 在扩容时计算hash值的方式不同。1.7在扩容时,需要重新计算位置h&(table.length-1)。而1.8不需要在此计算,根据hash值新参与运算的一位是1或者0,来确定位置是原位置+原表长或者原位置。

4.HashSet 是如何保证不重复的

看源码就可以发现,HashSet是基于HashMap实现的,而添加到HashSet中的值,是作为hashMap的key值进行put操作,而put操作中hash值相同,key也相同时,就会覆盖原来的值返回旧值,是不会产生重复的key值的。

5.final finally finalize 解释一下

final用于声明属性,方法和类,分别表示属性不可改变,方法不可覆盖、不可重载,类不可继承。
final修饰变量时,变量必须初始化。如果是非静态变量,可以在定义时初始化,可以在类中,方法中初始化等,不能在静态块中初始化。相反,修饰静态变量时,只能在定义时或者在静态块中初始化。final修饰对象时,对象的引用不可变,而不是对象。final修饰类时,类中的普通变量
finally 是处理异常的机制,finally只能用在try/catch语句中并且附带着一个语句块,finally代码总会执行,一般可以用来关闭数据库等,保证数据库安全。
finalize 是java允许一个对象将被回收之前做一些清理工作的设定,任何一个对象都会调用一次finalize方法。在子类中重写finalize可以实现一些清理或者关闭资源的工作,同时finalize是对象可以逃脱回收的最后一次机会,比如把自己赋值给未被回收的成员变量,和GC Roots重新建立联系。对象在第二次被回收时不会再次调用finalize。但据大佬说,这个方法不推荐使用的,因为finalize能做的,其实try-catch-finally完全可以完成。

5.强引用 、软引用、 弱引用、虚引用

强引用:只要强引用存在,垃圾回收器就不会回收掉被引用的对象。比如

Object obj = new Object();

软引用:描述有用但非必需的对象。当内存溢出前,将软引用的对象列入回收的范围进行二次回收,如果这次仍然没有足够的内存,那么会抛出内存溢出异常。
弱引用:比软引用更弱,描述又用但非必需的对象。下次JVM进行垃圾回收时,无论内存是否足够,弱引用的对象都会被回收。
虚引用:也称幽灵引用和幻引用。最弱的引用的类型,它的存在对对象的存活时间没有任何影响,只是在被回收时,能收到一条系统通知。

6. Java反射机制

(转)JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射机制常常被用获取类和属性,
也可以通过反射运行配置文件的内容,
还可以来越过泛型检查。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值