下面介绍Java面试中常见的对象加载及创建题目。
1、Java对象初始化顺序
先看一下如下笔试题目:
class Parent { public static int a = 2; public int b = 3; // 2 { System.out.println("this is anonymity b=" + b); } // 1 static { a = 4; System.out.println("this is static and a=" + a); } // 3 public Parent() { System.out.println("this is Parent constructor b="+b); } } public class Son extends Parent { public int b = 0; // 4 public Son() { System.out.println("this is Son constructor b="+b); } public static void main(String[] args) { new Son(); } }
当创建对象时,涉及到静态和非静态变量的初始化、静态和非静态匿名块的初始化以及构造函数的初始化,所以好多面试者不容易记住也不容易理解,下面我把这个类重构一下,变为如下的形式:
class Parent { public static int a; public int b; public(){ a = 2; static { a = 4; System.out.println("this is static and a=" + a); } } public (){ b = 3; System.out.println("this is Parent constructor b="+b); { System.out.println("this is anonymity b=" + b); } } } public class Son extends Parent { public (){ } public (){ System.out.println("this is Son constructor"); } // ... }
Javac编译器在生成字节码之前会将类调整为如上的样子,其中合成的函数
Parent.() -> Son. () -> Parent. () -> Son. ()
在重构
那么打印的结果肯定一目了然了,打印的结果如下:
this is static and a=4 this is anonymity b=3 this is Parent constructor b=3 this is Son constructor b=0
如果还想了解更多,比如Javac编译器为什么要进行这样的高速,可以参考《深入解析Java编译器:源码剖析与实例详解》一书。
2、对象创建的几种方式
要熟记对象创建的几种方式,如下:
(1)使用new
关键字 使用 new
关键字创建对象,实际上是做了两个工作,一是在内存中开辟空间,二是初始化对象;
(2)使用反射创建对象 反射创建对象分为两种方式,一是使用Class类的newInstance() 方法,二是使用Constructor类的newInstatance() 方法。Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数; Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数;
(3)使用clone()方法;
(4)使用序列化。
最广泛使用的应该就是使用new关键字和使用反射创建了。对于反射创建来说,如下:
Class.forName(className).newInstance();
调用forName()只会加载类,要得到对象需要调用newInstance()方法。这种创建方式在框架中用的多,就是因为forName()方法的参数是字符串类型,通过这个字符串来指定要加载的类,我们就可以通过配置的形式来指定加载的类型了,用起来很方便。另外需要注意,由于Class.forName()需要调用本地方法加载类,所以过程比较耗时,为了提高反射的性能,可以适当缓存这个获取到的对象。
3、对象的创建过程