美文网首页Java
Java 静态属性与实例属性的初始化

Java 静态属性与实例属性的初始化

作者: zhipingChen | 来源:发表于2019-04-23 16:09 被阅读5次

    类的初始化包括静态属性的初始化和实例属性的初始化,在加载类过程中的准备阶段会给静态属性分配存储空间,并根据属性的类型设置初始值,例如 int 类型静态属性会设置初始值为 0,布尔类型静态属性会设置初始值为 false;实例属性的初始化会在构造实例对象时发生。

    这里提到的静态属性不包括静态常量,静态常量会在准备阶段直接赋予指定的初始值。

    构造实例对象

    public class Test {
    
        {
            System.out.println("instance initialization");
        }
    
        static {
            System.out.println("static initialization");
        }
    
        public static void main(String[] args) {
            new Test();
            new Test();
        }
    }
    

    输出结果为:

    static initialization
    instance initialization
    instance initialization
    

    由此可知,静态属性的初始化发生在实例属性的初始化之前,且只发生一次,实例属性在每次创建实例对象会进行初始化。

    在加载阶段之后,会在内存中保存一个类的java.lang.Class对象,通过该Class对象来访问类中的各项数据,包括静态属性。所以静态属性只需要初始化赋值一次,生成Class对象后,通过Class对象来访问静态属性,实例属性则会在每次生成实例对象时初始化一次。

    加载、验证、准备阶段的顺序只是开始顺序,在某一个时间点,可能同时执行多个阶段的任务。例如加载阶段会将二进制字节流转换为内存中的一个Class对象,获取二进制信息后,会启动验证阶段对字节流进行安全验证,验证通过,准备阶段进行静态属性的内存分配和默认值设置,最后才会生成一个Class对象。

    构造子类实例对象

    public class Test extends Sup {
    
        {
            System.out.println("instance initialization");
        }
    
        static {
            System.out.println("static initialization");
        }
    
        public static void main(String[] args) {
            new Test();
            new Test();
        }
    }
    
    class Sup {
        {
            System.out.println("sup instance initialization");
        }
    
        static {
            System.out.println("sup static initialization");
        }
    }
    

    输出结果为:

    sup static initialization
    static initialization
    sup instance initialization
    instance initialization
    sup instance initialization
    instance initialization
    

    由此可知,在进行子类静态属性初始化时,若父类还没有进行静态初始化,则会先进行父类的静态初始化;在子类实例属性初始化时,若父类还没有进行实例属性初始化,则会先进行父类的实例属性初始化。并且每次构造实例对象都会进行实例属性初始化。

    静态属性的定义和使用

    public class Test {
    
        static {
            i = 1;
        }
    
        private static int i = 2;
    
        public static void main(String[] args) {
            System.out.println(Test.i);
        }
    }
    

    输出结果为:

    2
    

    上面提到在准备阶段会对静态属性设置类型默认值,由此可知,示例代码中的静态变量 i,在准备阶段默认值为 0。在初始化阶段,静态代码块和静态变量定义相当于两次赋值,首先设置 i=1,然后 i=2,所以输出值为 2。

    通过该示例可知,静态代码块和静态变量定义的赋值操作区分前后顺序,这里有一点需要注意:静态代码中只能访问定义在静态代码块之前的变量,即不能访问未初始化的变量。例如如下情况会编译报错:

    public class Test {
    
        static {
            i = 1;
            System.out.println(i); // 编译不通过 
        }
    
        private static int i = 2;
    }
    

    相关文章

      网友评论

        本文标题:Java 静态属性与实例属性的初始化

        本文链接:https://www.haomeiwen.com/subject/rtuvgqtx.html