Java干货——Part4




TheRa1nMan



1、什么是Java优先级队列(Priority Queue)?
PriorityQueue 是一个基于优先级堆的无界队列,它的元素是按照自然顺序(natural order)排序的。在创建的时候,我们可以给它提供一个负责给元素排序的比较器。PriorityQueue 不允许null 值,因为它们没有自然顺序,或者说它们没有任何的相关联的比较器。最后,PriorityQueue 不是线程安全的,入队和出队的时间复杂度是 O(log(n))。


2、你了解大 O 符号(big-O notation)么?你能给出不同的数据结构的例子么?
大O符号描述了当数据结构里面的元素增加的时候,算法的规模或者是性能,在最坏的场景下有多么好。
大O符号也可以用来描述其他的行为,比如内存消耗。因为集合类实际上是数据结构,我们一般用大O符号基于时间,内存和性能来选择最好的实现。大O符号可以对大量数据的性能给出一个很好的说明。


3、如何权衡是使用无序的数组还是有序的数组?
有序数组最大的好处在于查找的时间复杂度是 O(log n),而无序数组是 o(n)。
有序数组的缺点是插入操作的时间复杂度是 O(n),因为值大的元素需要往后移动来给新元素腾位置。相反,无序数组的插入时间复杂度是常量O(1)。


4、Java集合类框架的最佳实践有哪些?
1)根据应用的需要,正确选择要使用的集合的类型对性能非常重要,比如:假如元素的大小是固定的,而且能事先知道,我们就应该用Array 而不是ArrayList。
2)有些集合类允许我们指定初始容量。因此,如果我们能估计出存储元素的数目,我们可以设置初始容量来避免重新计算 hash值 或者是扩容。
3)为了类型安全,可读性和健壮性的原因总是要使用泛型。同时,使用泛型还可以避免运行时的 ClassCastException。
4)使用 JDK 提供的不变类(immutable class)作为 Map 的键可以避免为我们自己的类实现 hashCode() 和 equals() 方法。
5)编程的时候接口优于实现。
6)底层的集合实际上是空的情况下,返回长度是 0 的集合或者是数组,不要反回 null。


5、Enumeration 接口和 Iterator 接口的区别有哪些?
Enumeration 速度是 Iterator 的 2 倍,同时占用更少的内存。但是 Iterator 远比 Enumeration 安全,因为其他线程不能狗修改正在被 Iterator 遍历的集合里面的对象。同时,Iterator 允许调用者删除底层集合里面的元素,这对 Enumeration 来说是不可能的。


5、HashSet 和 TreeSet 有什么区别?
HashSet 是由一个 hash 表来实现的,因此它的元素是无序的。add(),remove(),contains() 方法的时间复杂度是 O(1)。
TreeSet 是由一个树形的结构来实现的,他里面的元素是有序的。因此,add(),remove(),contains() 方法的时间复杂度是 O(log n)。


6、Java中垃圾回收有什么目的?什么时候进行垃圾回收?
垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源。


7、System.gc() 和 Runtiome.gc() 会做什么事情?
这两个方法用来提示 JVM 要进行垃圾回收。但是,立即开始还是延迟进行垃圾回收是取决于 JVM 的。


8、finalize() 方法什么时候被调用?析构函数(finalization)的目的是什么?
垃圾回收器(garbage collector)决定回收某个对象时,就会运行该对象的 finalize() 方法,但是在 Java 中很不幸,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说 finalize() 可能永远不会执行,显然指望它做收尾工作是靠不住的。
那么, finalize() 究竟是做什么的呢?它最主要的用途是回收特殊渠道申请的内存。Java 程序有垃圾回收器,所以一般情况下内存问题不用程序员操心。但有一种 JNI(Java Native Interface)调用 non-Java 程序(C 或C++),finalize() 的工作就是回收这部分的内存。


9、如果对象的引用被置为 null,垃圾回收器是否会立即释放对象占用的内存?
不会,在下一个垃圾回收周期中,这个对象将是可被回收的。


10、Java 堆的结构是什么样子的?什么是堆中的永久代(Perm Gen space)?
JVM 的堆是运行时数据区,所有类的实例和数组都是在堆上分配内存。它在 JVM 启动的时候被创建。对象所占的堆内存是由自动内存管理系统(也就是垃圾收集器)回收。
堆内存是由存活和死亡的对象组成的。存活的对象是应用可以访问的,不会被垃圾回收。死亡的对象是应用不可访问尚且还没有被垃圾收集器回收掉的对象。一直到垃圾收集器把这些对象回收掉之前,他们会一直占据堆内存空间。


11、串行(serial)收集器和吞吐量(throughput)收集器的区别是什么?
吞吐量收集器使用并行版本的新生代垃圾收集器,它用于中等规模和大规模的应用程序。而串行收集器对大多数的小应用(在现代处理器上需要大概100M左右的内存)就足够了。


12、在Java 中,对象什么时候可以被垃圾回收?
对象与当前使用此对象的应用程序变得不可触及的时候,这个对象就可以被回收了。


13、JVM 的永久代中会发生垃圾回收么?
垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC 是非常重要的原因。请参考下 Java8:从永久代到元数据区。(Java8 中已经移除了永久代,新加了一个叫做元数据区的 native 内存区)

10-07 19:58