java是一门面向对象的语言,既然是面向对象的,那这个对象是从何而来呢?本文将与各位看官一起研究这个对象的由来问题。
回想人类的发展史,在以前,人们要是想得到一个锤子,首先会先准备一个石头,一条藤蔓(或者说是绳子),一根木棍;然后他会把木棍和石头用藤蔓绑好,这样就能得到一个锤子啦。在java中其实也是一样,首先你得准备一块内存(石头,藤蔓,木棍),然后对对象进行初始化(将石头,藤蔓,木棍绑好),这样就能得到一个对象啦。
当然实际的过程要比这复杂。在java中对象是类(class)的一个实例,就像石头锤子是锤子的一个实例一样(锤子还有铁锤子,木锤子),所以在java中想要拿到一个对象,首先就必须要有一个类。各位看官请看:
一个对象只有在相应的类完成初始化阶段后才能被创建出来,这就好像你想要创建出一个锤子,首先你得知道锤子是怎么样的(锤子应该是有一个敲击部位,一个可以握住的柄)。(关于类加载及其生命周期可以查阅楼主的另一篇文章)。而在java中,触发类的初始化,java虚拟机规范是这么定义的:
- 遇到new,getstatic,putstatic,或invokestatic这4条字节码指令时,如果类没有被初始化,则需要先触发其初始化;(简单来说就是new一个对象或者访问一个类的静态成员(包括访问静态成员变量:读与写,或访问静态方法)时);
- 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有被初始化,则需要先触发其初始化;
- 当初始化一个类的时候,发现其分类还没有进行初始化,则需要先触发其父类的初始化;
- 当虚拟机启动时,初始化包含main方法的那个类;
- 当使用JDK 1.7 的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化;
这里要记住的一点是有且只有这5种场景会触发类的初始化;
罗尼啰嗦这么大一段话,貌似还没到对象的产生上面,各位别急,想要得到一个对象,当然得需要做一些准备工作。好了,接下来就介绍java对象的创建:
- 使用new 关键字 如Person p = new Person();
- 使用Class的newInstance方法,这里得到class又有两种方法:1>Class clazz = Class.forName(“Person ”(完整的类名如java.lang.String));2>Class clazz = classLoader.loadClass(“Person ”(完整的类名如java.lang.String));1和2的不同在于他们使用的classLoader吧不同;
其实上面的两种方法都是一个流程首先得到初始化class,最后通过class 初始化对象,而后得到对象。只是new关键字把这两步一起做了,而第二种方法这是将两步分开。好了,到这里不知道大家是否有一个疑问,就是楼主不是说触发类的初始化有且只有上面的5种清楚,那么classLoader.loadClass属于哪一种呢?的确classLoader.loadClass不属于上面5种种的任何一种,之所以用classLoader.loadClass能得到class是因为classLoader.loadClass不是触发class,让虚拟机执行class的初始化,而是它自己就是执行类的初始化。(简单来说一种是让虚拟机执行初始化得到类,一种是用自己的方法初始化得到类)
好了,最后要讲讲类初始化得到了什么,其实类初始化化就是对类里面的静态成员进行赋值的一个操作(当然在赋值前就已经对该静态变量分配了内存,并赋予了初始值即2进制为全0);而完成类的初始化,然后就是对象的初始化,即对对象的成员变量赋值。最后我们就能得到对象啦。