Java类的加载一共分为两部分,第一步首先是加载类型信息,就是把该类的class类型信息加载到内存中,加载class类型信息的时候触发的操作有-->会先进行static静态属性的初始化,然后是调用静态代码块;第二步是使用类型信息来创建对象。这个阶段会触发的操作是---->先进行属性的初始化操作,然后执行代码块,最后调用构造方法。
静态属性和静态代码块只有在类型被加载的时候才会进行初始化和执行静态代码块。(所有的对象都是通过类型信息的创建,所以所有对象通过getClass()方法获取到的类型信息都是相等的,使用“==”来比较时你会发现两者相等,这也就是为什么static属性是所有对象共享的了,因为static属性是保存在类型信息里的)
static属性的初始化和static静态代码块的调用执行,只有在类型第一次加载的时候才会有响应(一种直观但实际错误的描述方法就是,第一次创建对象的时候会触发类型的加载,即会触发静态属性的初始化和静态代码块的执行,但是第二次创建对象的时候不会再进行静态属性的初始化和静态代码块的调用了)
1、第一种情形(还未加载类型信息)
1.1 加载类型信息-->这一步会先初始化静态属性,然后执行静态代码块
1.2 使用类型信息来创建对象
1.3 创建对象的过程是-->初始化属性,然后执行代码块,最后是调用构造方法
2、第二种情形(已经加载类型信息了)
2.1 使用类型信息来创建对象
2.2 创建对象的过程是-->初始化属性,然后执行代码块,最后是调用构造方法
3、第三种情形(没有加载类型信息,并且有继承父类)
3.1 加载类型信息,先加载基类的类型信息,然后加载扩展类的类型信息,过程是-->先进行基类静态属性的初始化,然后进行基类静态代码块的调用,当基类的操作完成后,再进行扩展类的操作,先进行静态属性的初始化,然后进行静态代码块的调用。
3.2 使用类型信息来创建对象(我的理解和实践是这样,具体还需大家一起验证是否正确)
3.3 创建对象的顺序时,先基类,然后再是扩展类。创建对象中包含的顺序是-->先初始化属性-->然后调用代码块-->最后调用构造方法。当每一个类的创建过程完成之后,就往下一级的扩展类进行初始化
4、更复杂的情况也无非是有些类的类型信息已经加载,有些类型信息没有加载而已。如果没有加载那么就先进行加载就好。
会导致类型信息被加载进来的一些情况(目前认识还不是很深,可能描述不一定正确,大家作为一个参考就好)
1 使用Class.forName()方法来反射加载类型信息
2 访问类的静态属性(不包含编译期常量)
3 创建对象
4 访问“非编译期常量”
public static final String SCHOOL="GDUT";这种叫做编译期常量
public static final String SCHOOL=new Integer(22).toString();这种叫做非编译期常量
如果上述内容有误的话,还请指出,以免误人子弟!
--------------------------------------------------------------------------BaseClass--------------------------------------------------------------------------------
package init;
public class BaseClass {
public BaseClass() {
System.out.println("----调用BaseClass的空参构造方法-----");
}
public BaseClass(Integer id) {
System.out.println("如果id的值不等于0,那么就说明属性的初始化顺序是优先于构造器的:" + this.id);
this.id = id;
}
private Integer id = 123456;
static {
System.out.println("----BaseClass被加载进来了-----");
}
{
System.out.println("-----BaseClass代码块执行----");
}
}
--------------------------------------------------------------------------User--------------------------------------------------------------------------------
package init;
public class User extends BaseClass {
private String name = "往事如烟";
public User() {
System.out.println("----user-----name=" + name);
System.out.println("如果name的值是往事如烟,说明属性的初始化顺序优先构造器");
}
static {
System.out.println("----User被加载进来了-----");
}
{
System.out.println("----User代码块调用-----");
}
}
-------------------------------------------------------------------------InitTest--------------------------------------------------------------------------------
package init;
import org.junit.Test;
public class InitTest {
@Test
public void test1(){
//第一次会有加载class类型的痕迹
User user=new User();
System.out.println("-----------------------------------");
//之后不会有加载类的痕迹
User user1=new User();
}
}