美文网首页编程读书笔记程序员
创建对象只是开辟个堆内存那么简单吗?

创建对象只是开辟个堆内存那么简单吗?

作者: 安宁_Ann | 来源:发表于2017-08-13 19:40 被阅读284次

java对象

对象的创建

java的对象是在运行时创建的,创建对象的的触发条件有以下几种:

  1. 用new语句创建对象,这是最常用的创建对象方法。
  2. 运用反射手段,调用java.lang.reflect.Constructor类的newInstance()实例方法。
  3. 调用对象的clone()方法。
  4. 运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法。

对象创建过程

java对象在创建时需要在方法区的运行时常量池去查找该类的符号引用,如果没有发现符号引用,说明该类还没有被JVM加载,所以要先进行JVM的加载。当JVM加载完时,会在java堆中分配内存。分配内存时会根据堆内存是否规整来分别进行两种方式的分配。
1.指针碰撞
把内存分为可用的和已用的,在中间放置一个指针,如果要分配对象的空间,则把内存的指针向可用的一端移动当前需要分配对象大小的距离。
2.空闲列表
当内存并不是很规整时,需要一个列表来维护那些列表是可用的,那些是不可用的。

当内存分配完成后需要对分配到内存空间的对象赋予零值(静态字段在类加载中就已经有值,所以不需要赋零值),接下来需要设置对象头的信息:如设置该对象的哈希码,属于哪个类,GC分代年龄等信息。从虚拟机的角度来看至此一个对象就创建完成,但是在java程序的角度看,对象的创建才刚刚开始,因为对象的值还没有设定,对象值得设定是由对象初始化化来完成的,初始化就是调用构造方法过程。

对象的初始化

当对象创建完成后,接下来就是进行对象的初始化了,也就是去执行构造方法。

父类的初始化

当子类对象创建之前首先会调用父类的构造函数,也就是会初始化父类,但是父类并没有被创建,也就是并没有在堆中给父类分配新的存储空间,而只是对父类的变量进行了赋值。从而达到子类可以使用父类的属性和方法的目的。

静态类的初始化

当一个类中有static修饰的方法或者是变量的话,那么当这个静态方法被第一次调用的时候,那么这个类就会初始化,就会调用此类的类构造器(在类加载过程中被JVM自动加入),类构造器只初始化一次,触发条件为实例构造器执行,或者是静态任何一个静态成员被引用,也就是说这个类只会初始化一次。

普通类的初始化

区别与父类和静态类的初始化,普通类的初始化是建立在对象创建之上的,也就是对象创建完成后会自动的去调用构造方法进行初始化。

对象创建及初始化实例

看完上面文字上的简单说明总感觉少些什么东西?就像一碗牛肉拉面没有卤鸡蛋一样。所以笔者要通过一个java代码来将上面的知识点串起来,让你有一个更清晰的认识。


public class Parent {
    int a = 1;
    static int b = 2;

    // 静态代码块
    static {
        System.out.println("执行Parent静态代码块:b =" + b);
        b++;
    }

    // 普通代码块
    {
        System.out.println("执行Parent普通代码块: a =" + a);
        System.out.println("执行Parent普通代码块: b =" + b);
        b++;
        a++;
    }

    // 无参构造函数
    Parent() {
        System.out.println("执行Parent无参构造函数: a =" + a);
        System.out.println("执行Parent无参构造函数: b =" + b);
    }

    // 有参构造函数
    Parent(int a) {
        System.out.println("执行Parent有参构造函数: a =" + a);
        System.out.println("执行Parent有参构造函数: b =" + b);
    }

    // 方法
    void fun() {
        System.out.println("执行Parent的fun方法");
    }

}

public class Child extends Parent {
    int c = 1;
    static int d = 2;
    // 静态代码块
    static {
        System.out.println("执行Child静态代码块:d =" + d);
        d++;
    }
    // 普通代码块
    {
        System.out.println("执行Child代码块: c =" + c);
        System.out.println("执行Child代码块: d =" + d);
        c++;
        d++;
    }

    // 构造函数
    Child() {
        System.out.println("执行Child构造函数: c =" + c);
        System.out.println("执行Child构造函数: d =" + d);
    }

    // 方法
    void fun() {
        System.out.println("执行Child的fun方法");
    }

}

public class Test {
    public static void main(String[] args) {
        Child demo = new Child();
        demo.fun();
        System.out.println("…………………………………………………………………………………………………………………………");
        Child child = new Child();
        child.fun();
    }
}

上面有三个很简单的类,一个Parent,一个Child,一个Test。当执行Test的main方法是会输出什么呢?

//输出结果
执行Parent静态代码块:b =2
执行Child静态代码块:d =2
执行Parent普通代码块: a =1
执行Parent普通代码块: b =3
执行Parent无参构造函数: a =2
执行Parent无参构造函数: b =4
执行Child代码块: c =1
执行Child代码块: d =3
执行Child构造函数: c =2
执行Child构造函数: d =4
执行Child的fun方法
…………………………………………………………………………………………………………………………
执行Parent普通代码块: a =1
执行Parent普通代码块: b =4
执行Parent无参构造函数: a =2
执行Parent无参构造函数: b =5
执行Child代码块: c =1
执行Child代码块: d =4
执行Child构造函数: c =2
执行Child构造函数: d =5
执行Child的fun方法

下面我们一起来看看这些输出是这么一步步产生的。





注:本文的重点不是虚拟机有关的详细执行,之后会专门写一个关于虚拟机加载的文章,所以有关细节问题都一笔带过了

相关文章

  • 创建对象只是开辟个堆内存那么简单吗?

    java对象 对象的创建 java的对象是在运行时创建的,创建对象的的触发条件有以下几种: 用new语句创建对象,...

  • 堆栈内存

    JS中的内存:堆内存和栈内存 堆内存是用来存储引用数据类型值的(例如:创建函数和创建对象,就像开辟一个堆内存,把代...

  • 第七天

    数组 数组是引用数据类型中的对象数据类型(特殊对象)创建一个数组,也要开辟一个堆内存,堆内存中存储数据对象中的键值...

  • 1.17 初识数组

    数组是引用数据类型中的对象数据类型(特殊对象)创建一个数组,开辟一个堆内存,堆内存中存储数组对象中的键值对let ...

  • 对象的内存存储细节

    1.对象的存储细节 通过类创建对象开辟存储空间,通过new方法创建对象会在堆内存中开辟一块存储空间初始化所有属性返...

  • Java匿名对象与构造器

    匿名对象创建一个对象,没有把它赋值给任何一个变量匿名对象只是在堆中开辟一块新的内存空间,但是没有把该空间地址赋值给...

  • Java 自定义对象内存图

    自定义类 属于引用数据类型 它创建出的对象在 堆内存中开辟内存空间(内存中包括对象的属性 ) 对象调用方法就是在 ...

  • Java 对象克隆

    所谓的对象克隆描述的概念就是进行对象的赋值,当一个对象创建完成之后实际上都会自动的开辟内存空间,在每一块堆内存空间...

  • volatile 关键字

    线程内存,当一个线程创建对象instance时,在堆内存中创建对象,引用指向堆内存的地址。当对这个引用内容进行修改...

  • 内存释放(堆内存)和作用域(栈内存)销毁

    内存释放(堆内存)和作用域(栈内存)销毁对象数据类型或者函数数据类型在定义的时候会首先开辟一个堆内存// 堆内存的...

网友评论

    本文标题:创建对象只是开辟个堆内存那么简单吗?

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