Java类型的加载和实例的生成

Java的每一个类型在被使用前,是需要加载进虚拟机的。且一个类型只会被加载一次,但是Java类型是可以用来创建多个实例的,所以初始化过程是会进行多次的。那哪些过程是单次的?哪些过程是和实例创建关联的?

        首先,类型要使用需要被装载进虚拟机,这个阶段我们称为Loading,主要任务是通过类型的完全限定名,读取class文件,产生一个代表该类型的二进制数据流,解析class文件到方法区内的内部数据结, 构建一个表示该类型的java.lang.Class类的实例。接下来的任务是链接(Linking),包括验证,准备,解析,其中验证不是链接的目的,只是为了安全和准确,准备是给变量分配内存并赋缺省值,解析才是对应链接的本质工作,解析就是将分配的这些存储实际内容的内存地址和虚拟机常量池中的符号关联起来,主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用限定符7类符号引用进行。然后就是类型初始化,主要是对静态变量赋值和执行静态代码块。注意这里没有类型的构造方法的执行,以上这些过程一个类只会执行一次。

        类型加载进虚拟机了就可以引用静态成员或者进行实例化了,实例化的过程是先分配内存,然后进行实例初始化,实例初始化过程是先给成员变量赋值,然后调用构造方法,注意这个先后顺序。其中每次实例化都会伴随这些动作,这一点要和上面类型初始化区分开来。这里举个实际例子来看看效果

public class A {

    public static String x = "p";

    static {
        System.out.println("static");
    }

    public A() {
        System.out.println("A construct");
    }
}

public class Main {

    public static void main(String[] args) {
        System.out.println(A.x);
    }
}

这里可以很明显的看到没有执行A的构造方法,只有当你产生A的实例的时候才需要执行构造方法。
另外再举个例子,如果A类型中有一个B类型的非静态成员变量B b = new B(),B类型中有一个非静态成员变量A a = new A(),请问在实例化A时会发生什么,发生StatckOverflow异常,为什么呢?因为在实例A化时,发现一个非静态成员变量b,需要初始化b,而实例化B时发现一个非静态成员a,于是又要先实例化A,导致了A和B的初始化动作造成无限循环,循环的动作是A和B的实例初始化动作<init>,注意这里在不断的进行A和B实例的创建,是多个不同的A和B实例,这个行为和A引用B,B引用C,C引用D,D引用E。。。这种循环是一个道理。根本原因时A和B的实例初始化动作的互相循环调用。(简单来说就是a1->b1->a2->b2->a3->b3......)
当我们把A、B成员变量定义为静态的时候,就不会陷入无限循环了,这是为什么呢?因为静态变量的初始化是类加载时完成,实例化A,先要加载A,加载的时候需先初始化A里面的静态成员B=null,然后紧接着给B赋值,这个时候需要加载B,加载B时给静态成员A赋缺省值null,然后给A赋值,这个时候A已经标记为装载了,就可以实例化了,然后B里面的A实例化完成,所以B也就紧接着实例化完成,然后A也实例化完成。
这2个的区别就在于非静态变量是跟实例走,要实例化一个类型,就要给实例里的非静态变量赋值,第一个例子里有非静态变量跟着实例,所以不停的创建非静态变量,而第二个例子里没有,所以实例能够结束创建。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值