26、说说has a与is a的区别。
is a是典型的“一般到特殊”的关系,也就是典型的继承关系。例如Apple is a Fruit。那么Apple是一种特殊的Fruit,也就是说Apple继承了Fruit。
has a是典型的“组合”关系。比如Wolf has a Leg,也就是Leg组合成了Wolf。
需要指出的是:由于继承会造成了对父类的破坏,因此有时候可以通过组合来代替的继承。使用继承的好处:程序语义更好理解。坏处是:子类可能重写父类方法,不利于父类封装;使用组合则造成语义的混淆,但组合类不会重写被组合类的方法,因此更利于被复合类的封装。
27、ClassLoader如何加载class 。
jvm里有多个类加载,每个类加载可以负责加载特定位置的类,例如,bootstrap类加载负责加载jre/lib/rt.jar中的类, 我们平时用的jdk中的类都位于rt.jar中。extclassloader负责加载jar/lib/ext/*.jar中的类,appclassloader负责classpath指定的目录或jar中的类。除了bootstrap之外,其他的类加载器本身也都是java类,它们的父类是ClassLoader。
4.抽象类的作用
28、GC是什么? 为什么要有GC?
GC是垃圾收集的意思(Gabage Collection),内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的。
Java的System类和Runtime类都提供了“通知”程序进行垃圾回收的方法,例如如下代码:
Systme.gc();
或
Runtime.getInstance().gc();
但这两个方法只是“通知”Java进行垃圾回收,但实际上JVM何时进行垃圾回收,还是由JVM自己决定。
29、垃圾回收的优点和原理。并考虑2种回收机制。
传统的C/C++等编程语言,需要程序员负责回收已经分配的内存。显式进行垃圾回收是一件比较困难的事情,因为程序员并不总是知道内存应该何时被释放。如果一些分配出去的内存得不到及时回收,就会引起系统运行速度下降,甚至导致程序瘫痪,这种现象被称为内存泄漏。总体而言,显式进行垃圾回收主要有如下两个缺点:
A.程序忘记及时回收无用内存,从而导致内存泄漏,降低系统性能。
B.程序错误地回收程序核心类库的内存,从而导致系统崩溃。
与C/C++程序不同,Java语言不需要程序员直接控制内存回收,Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收(Garbage Collection,也被称为GC)。通常JRE会提供一条后台线程来进行检测和控制,一般都是在CPU空闲或内存不足时自动进行垃圾回收,而程序员无法精确控制垃圾回收的时间和顺序等。
实际上,垃圾回收机制不可能实时检测到每个Java对象的状态,当一个对象失去引用后,它也不会被立即回收,只有等接下来垃圾回收器运行时才会被回收。
对于一个垃圾回收器的设计算法来说,大致有如下可供选择的设计:
A.串行回收(Serial)和并行回收(Parallel):串行回收就是不管系统有多少个CPU,始终只用一个CPU来执行垃圾回收操作;而并行回收就是把整个回收工作拆分成多部分,每个部分由一个CPU负责,从而让多个CPU并行回收,并行回收的执行效率很高,但复杂度增加,另外也有其他一些副作用,比如内存碎片会增加。
B.并发执行(Concurrent)和应用程序停止(Stop-the-world):。Stop-the-world的垃圾回收方式在执行垃圾回收的同时会导致应用程序的暂停。并发执行的垃圾回收虽然不会导致应用程序的暂停,但由于并发执行垃圾回收需要解决和应用程序的执行冲突(应用程序可能会在垃圾回收的过称中修改对象),因此并发执行垃圾回收的系统开销比Stop-the-world更好,而且执行时也需要更多的堆内存。
C.压缩(Compacting)和不压缩(Non-compacting)和复制(Copying):为了减少内存碎片,支持压缩的垃圾回收器会把所有的活对象搬迁到一起,然后将之前占用的内存全部回收。不压缩式的垃圾回收器只是回收内存,这样回收回来的内存不可能是连续的,因此将会有较多的内存碎片。较之压缩式的垃圾回收,不压缩式的垃圾回收回收内存快了,而分配内存时就会更慢,而且无法解决内存碎片的问题。复制式的垃圾回收会将所有可达对象复制到另一块相同的内存中,这种方式的优点是垃圾及回收过程不会产生内存碎片,但缺点也很明显,需要拷贝数据和额外的内存。
30、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
对于Java程序中对象而言,如果这个对象没有任何引用变量引用它,那么这个对象将不可能被程序访问,因此可认为它是垃圾;只要有一个以上的引用变量引用该对象,该对象就不会被垃圾回收。
对于Java的垃圾回收器来说,它使用有向图来记录和管理堆内存中的所有对象,通过这个有向图就可以识别哪些对象是“可达的”(有引用变量引用它就是可达的),哪些对象是“不可达的”(没有引用变量引用它就是不可达的),所有“不可达”对象都是可被垃圾回收的。
但对于如下程序:
class A
{
B b;
}
class B
{
A a;
}
public class Test
{
public static void main(String[] args)
{
A a = new A();
a.b = new B();
a.b.a = a;
a = null;
}
}
上面程序中A对象、B对象,它们都“相互”引用,A对象的b属性引用B对象,而B对象的a属性引用A对象,但实际上没有引用变量引用A对象、B对象,因此它们在有向图中依然是不可达的,因此也会被当成垃圾处理。
程序员可以手动执行System.gc(),通知GC运行,但这只是一个通知,而JVM依然有权决定何时进行垃圾回收。