您的位置:首页 > 其它

JAVA对象的创建过程

2016-12-13 10:27 190 查看
JAVA是一门面向对象的语言,在JAVA程序运行过程中无时无刻都有对象被创建出来。在语言层面上,创建对象(如克隆、反序列化)通常仅仅是一个new关键字而已,而在虚拟机中对象的创建过程是什么样的呢?

虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程,在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定。

下面看一个例子引用自:http://blog.sina.com.cn/s/blog_687ab1d70100r9gv.html

首先看一个类Dog:

Java代码

package cn.tutorinfo.classloader;  

  

public class Dog {  

    private String name;  

  

    // 静态成员变量  

    private static DogProfile profile = new DogProfile("公", 3);  

  

    // 静态代码块  

    static {  

        System.out.println("Dog的静态代码区域");  

    }  

  

    // 静态方法  

    public static void doSomething() {  

        System.out.println("执行Dog类中的静态方法 doSomething()方法");  

  

    }  

  

    // 构造方法  

    Dog(String name) {  

        this.name = name;  

  

        System.out.println("Dog的名字是:" + name);  

    }  

  

    public static void main(String[] args) {  

        new Dog("京巴");    

    //  Dog.doSomething();  

    //  System.out.println(Dog.profile);  

    }  

}  

  

class DogProfile {  

    private String male;  

    private Integer age;  

  

    DogProfile(String male, Integer age) {  

        this.male = male;  

        this.age = age;  

        System.out.println("DogProfile构造方法");  

    }  

  

    @Override  

    public String toString() {  

        return new StringBuilder("Dog的雌雄是:").append(this.male).append(",年龄是:").append(this.age).toString();  

    }  

}  

 

 

 

当 main方法中代码是new Dog()时,程序的输出结果,:

Java代码

DogProfile构造方法  

Dog的静态代码区域  

Dog的名字是:京巴  

 当main方法中代码是Dog.doSomething()时,程序输出结果是:

Java代码

DogProfile构造方法  

Dog的静态代码区域  

执行Dog类中的静态方法 doSomething()方法  

 当main方法中代码是System.out.println(Dog.profile) 时,程序输出结果是:

Java代码

DogProfile构造方法  

Dog的静态代码区域  

Dog的雌雄是:公,年龄是:3  

 

 

Dog类中我分别设置了一个普通的属性和一个静态属性,同时类中还存在一个static 代码区域,通过分析程序的结果,我们可以大致了解了对象的创建过程:

1. 所有的类都是在对其第一次使用时,动态加载到JVM中。当首次创建类型为Dog的对象时,或者Dog类的静态方法,静态属性域首次被访问时,java解释器查找classPath,定位到Dog.class文件

 

2. 载入Dog.class文件,生成一个Class类型对象,所有有关的静态初始化动作都会执行,静态代码块,静态成员属性。 并且这种初始化动作只在Class对象首次加载时候进行一次。

 

3. 当用new Dog()创建对象时,首先JVM在堆heap上为Dog对象分配足够的存储空间

 

4. 存储空间清空,自动将Dog对象中的所有基本类型数据都设置成了默认值,对象引用被设置为null

 

5. 执行所有在字段定义处的一些初始化操作

 

6. 调用构造器方法。(没有继承)

 

如此一来,便创建了这个对象.

 

 

 

以上是不存在继承的情况下的执行过程,如果是存在多重继承的情况下呢?

首先看代码:

Java代码

package cn.tutorinfo.classloader;  

  

class DogProfile {  

    private String male;  

    private Integer age;  

  

    DogProfile(String male, Integer age) {  

        this.male = male;  

        this.age = age;  

        System.out.println("DogProfile构造方法");  

    }  

  

    @Override  

    public String toString() {  

        return new StringBuilder("Dog的雌雄是:").append(this.male).append(",年龄是:").append(this.age).toString();  

    }  

}  

  

class Dog {  

    private String name;  

  

    // 静态成员变量  

    private static DogProfile profile = new DogProfile("公", 3);  

  

    // 静态代码块  

    static {  

        System.out.println("Dog的静态代码区域");  

    }  

  

    // 静态方法  

    public static void doSomething() {  

        System.out.println("执行Dog类中的静态方法 doSomething()方法");  

  

    }  

  

    // 构造方法  

    Dog(String name) {  

        this.name = name;  

  

        System.out.println("Dog的名字是:" + name);  

    }  

  

}  

  

class JingbaDog extends Dog {  

  

    private static DogProfile profile = new DogProfile("母", 2);  

  

    JingbaDog(String name) {  

        super(name);  

        System.out.println("JingbaDog的名字是:" + name);  

  

    }  

  

}  

  

public class DogExamp extends JingbaDog {  

  

    private static DogProfile profile = new DogProfile("母", 1);  

  

    DogExamp(String name) {  

        super(name);  

        System.out.println("DogExamp的名字是:" + name);  

    }  

  

    //生成一个DogExamp对象  

    public static void main(String[] args) {  

        new DogExamp("不知名");  

  

    }  

}  

 

 

main方法中就只生成一个DogExamp对象,程序输出是:

Java代码

1. DogProfile构造方法  

2. Dog的静态代码区域  

3. DogProfile构造方法  

4. DogProfile构造方法  

5. Dog的名字是:不知名  

6. JingbaDog的名字是:不知名  

7. DogExamp的名字是:不知名  

 

我们结合没有继承的情况下的流程,以及上述的结果分析下:

 

java解释器在类路径中查找DogExamp.class文件后,会根据继承规则,定位JiingbaDog.class 和Dog.class. 分别载入后生成相应的Class对象,此时按照上述的流程,依次执行静态初始化的动作.

首先在Dog类中执行静态初始化,在初始化静态属性profile时,导致实例化Dogprofile对象,输出第一行。然后执行静态代码块,导致输出第二行。

接下来,子类JingbaDog中执行静态初始化动作,同样初始化了profile静态属性,导致实例化DogProfile对象,输出第三行,同理,DogExamp中的静态成员初始化,输出第4行。

 

静态初始化结束后,按照类的继承关系的构造方法的调用,首先执行基类Dog的构造方法,输出第5行

然后执行JingbaDog的构造方法,输出第6行。

 

最后执行自身的构造方法 输出第7行.

 

 

 

根据以上分析,我们得出的结论是:

1. 当首次创建一个类的对象时(此时即是调用构造方法,构造方法也是隐式的静态),或者类的静态方法被调用,静态成员属性被引用时,java解释器都将查找类对象的class文件

 

2. 载入class文件后生成Class对象时,会执行静态初始化所有动作。(包括父类的静态成员和静态代码块)

 

3. 执行类定义在字段处的初始化动作

 

4. 递归调用构造器执行构造方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: