美文网首页
Java基础-类与对象初始化

Java基础-类与对象初始化

作者: Allen赵子强 | 来源:发表于2019-01-14 23:10 被阅读0次

    Java源码(.java文件)编译后生成字节码(.class文件),一个.java文件如果定义了多个类,则会为每个类生成一个.class文件。然后jvm虚拟机加载并运行字节码文件。jvm在运行一个Java程序时,采用的是懒加载,并不会把CLASSPATH下的所有类文件一次性加载进来。一个类在第一次被使用时将被jvm加载进来,第一次使用一般有这几种情况:
    1.创建这个类的第一个对象;
    2.第一次使用这个类的static属性或static方法;
    3.加载某个类时,它的超类还没被加载,此时需要先加载超类;
    4.反射操作,如Class.forName()

    类的初始化

    当一个类被java虚拟机加载时,它的static属性将被初始化,它的static方法块将被执行,且这个初始化动作只会执行一次。

    class Marker {
        public Marker(int i) {
            System.out.println(i);
        }
    
        public Marker(String s) {
            System.out.println(s);
        }
    }
    
    class Foo {
    
        public static Marker marker = new Marker("foo static field");
    
        static {
            System.out.println("foo static block");
        }
    }
    
    public class LearnTest extends TestCase {
    
        public static void main(String[] args) {
            Foo foo1 = new Foo();
            Foo foo2 = new Foo();
        }
    }
    

    执行上述代码,输出:

    foo static field
    foo static block

    可以看到当为类Foo创建第一个对象时(此时类Foo将被jvm加载),它的static属性及static方法块将初始化,且只会初始化一次。除了生成第一个对象时会加载类,第一次使用类的static属性或方法也将加载类。

    class Marker {
        public Marker(int i) {
            System.out.println(i);
        }
    
        public Marker(String s) {
            System.out.println(s);
        }
    }
    
    class Foo {
    
        public static int i = 1;
    
        public static Marker marker = new Marker("foo static field");
    
        static {
            System.out.println("foo static block");
        }
    
    
    }
    
    public class LearnTest extends TestCase {
    
        public static void main(String[] args) {
            System.out.println(Foo.i);
            System.out.println(Foo.i);
        }
    }
    

    执行上述代码,输出:

    foo static field
    foo static block
    1
    1

    可以看到当第一次使用到类Foo的static属性时(此时类Foo将被jvm加载),它的static属性及static方法块将初始化,且只会初始化一次。

    结论:static属性及static方法块将在类被加载进jvm时执行初始化,由于类的加载只发生一次,所以static也只会初始化一次。

    对象的初始化

    java提供了constructor(构造器)来执行对象的初始化,每个类都有一个默认的空构造器,不执行任何动作,你也可以自己定义任意数量的构造器来定义对象的初始化行为。但是一个对象在初始化时并不仅仅是执行构造器中定义的代码,而是按顺序完成初始化动作,执行构造器仅仅是这初始化动作中的一个。

    直接看一段示例代码:

    class Marker {
        public Marker(int i) {
            System.out.println(i);
        }
    
        public Marker(String s) {
            System.out.println(s);
        }
    }
    
    class Super {
    
        private static Marker marker = new Marker(0);
    
        static {
            System.out.println(1);
        }
    
        private Marker marker1 = new Marker(4);
    
        public Super() {
            System.out.println(5);
        }
    }
    
    class Sub extends Super {
    
        private static Marker marker = new Marker(2);
    
        static {
            System.out.println(3);
        }
    
        private Marker marker1 = new Marker(6);
    
        public Sub() {
            System.out.println(7);
        }
    }
    
    public class LearnTest extends TestCase {
    
        public static void main(String[] args) {
            Super s1 = new Sub();
            Super s2 = new Sub();
        }
    }
    

    以上程序将输出:

    0
    1
    2
    3
    4
    5
    6
    7
    4
    5
    6
    7

    先说一下继承,当一个子类对象被实例化出来时,会隐式地自动实例化一个它的父类对象,这个父类对象只能由子类对象通过super关键字访问;如果父类是另一个类的子类,则继续向上传递进行实例化,最后实例化出来的子类对象在内存中如下图(其中子类继承父类,父类继承基类):

    如图所示,子类对象内部隐式地存在一个父类对象,父类对象内部隐式地存在一个基类对象。

    理解了继承,再来看下对象的初始化顺序:

    1. 由于是第一次实例化Sub类的对象,将加载Sub类,而Sub类继承Super类,所以先把Super类加载进jvm,此时Super类的static属性及static方法块初始化,对应输出0和1;
    2. Super类加载完毕后,开始加载Sub类,此时Sub类的static属性及static方法块初始化,对应输出2和3;
    3. 类加载完毕后开始实例化对象,由于Sub类继承Super类,所以Sub类对象包含Super类对象,先将Super类对象实例化出来。Super类对象的属性被初始化,对应输出4。接着Super类对象的构造器被执行,对应输出5;
    4. Super类的对象实例化完毕后,开始实例化Sub类的对象。Sub类对象的属性被初始化,对应输出6,最后Sub类对象的构造器被执行,对应输出7。整个对象实例化动作结束。
    5. 当再次实例化另一个Sub类对象时,由于类已经被加载过,static属性及方法块不再初始化,仅执行属性及构造器初始化动作,对应输出4、5、6、7。

    其他

    以上对类的加载介绍其实是很简略的,实际上jvm对类的加载还分为加载、链接、初始化等步骤,而这些步骤也是可以分步完成的,比如我们第一次使用类的static final常量,仅仅会执行加载、链接两个步骤,但不会初始化类,所以类的static属性及static方法块将不会初始化。

    相关文章

      网友评论

          本文标题:Java基础-类与对象初始化

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