JVM-对象的实例化内存布局与访问定位

笔记均来自于尚硅谷官方视频,为了本人复习使用,无其他目的
尚硅谷官方视频

一、对象的实例化

1.创建对象的方式

1). 使用new关键字创建对象

这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们可以调用任意的构造函数(无参的和有参的)去创建对象。比如:

Student stu1 = new Student(123);

2). 使用Class类的newInstance方法(反射机制)

我们也可以通过Java的反射机制使用Class类的newInstance方法来创建对象,事实上,这个newInstance方法调用无参的public权限的构造器创建对象,比如:

Student stu2 = Student.class.newInstance(); 

3). 使用Constructor类的newInstance方法(反射机制)

java.lang.relect.Constructor类里也有一个newInstance方法可以创建对象,该方法和Class类中的newInstance方法很像,但是相比之下,Constructor类的newInstance方法更加强大些,我们可以通过这个newInstance方法调用有参数的和私有的构造函数,比如:

public class Student {

    private int id;

    public Student(Integer id) {
        this.id = id;
    }

    public static void main(String[] args) throws Exception {

        Constructor<Student> constructor =Student.class.getConstructor(Integer.class);
        Student stu3 = constructor.newInstance(123);
    }
}

使用newInstance方法的这两种方式创建对象使用的就是Java的反射机制,事实上Class的newInstance方法内部调用的也是Constructor的newInstance方法。

4). 实现Cloneable接口并实现其定义的clone方法来创建对象

当调用一个对象的clone方法,JVM都会帮我们创建一个新的、一样的对象,用clone方法创建对象的过程中并不会调用任何构造函数,要想使用clone方法,我们就必须先实现Cloneable接口并实现其定义的clone方法。

public class Student implements Cloneable {
    private int id;

    //空参构造器
    public Student() {

    }
    //有参构造器
    public Student(Integer id) {
        this.id = id;
    }

    //实现Cloneable接口中的clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student [id=" + id + "]";
    }

    public static void main(String[] args) throws Exception {


        System.out.println("-----------使用Clone方法创建对象----------------");
        Student stu4 = (Student) stu3.clone();
        System.out.println(stu4);

    }
}

5). 使用(反)序列化机制创建对象
序列化:java对象转化为二进制流(字节序列)的过程
反序列化:二进制流(字节序列)恢复成java对象的过程

序列化的作用:对象转换为有序字节流,以便在网络上传输或者保存在本地文件中。
  当我们反序列化一个对象时,JVM会给我们创建一个单独的对象,在此过程中,JVM并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口(标识接口),

public class Student implements Cloneable,Serializable {
    private int id;

    //空参构造器
    public Student() {

    }
    //有参构造器
    public Student(Integer id) {
        this.id = id;
    }

    //实现Cloneable接口中的clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student [id=" + id + "]";
    }

    public static void main(String[] args) throws Exception {

        System.out.println("-----------使用Clone方法创建对象----------------");
        Student stu4 = (Student) stu3.clone();
        System.out.println(stu4);


        System.out.println("-----------使用(反)序列化机制创建对象----------------");
        // 写对象
        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.bin"));
        output.writeObject(stu4);
        output.close();

        // 读取对象
        ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.bin"));
        Student stu5 = (Student) input.readObject();
        System.out.println(stu5);

    }
}

完整代码与截图

package jvm;

import java.io.*;
import java.lang.reflect.Constructor;

public class Student implements Cloneable, Serializable {
    private int id;

    //空参构造器
    public Student() {

    }
    //有参构造器
    public Student(Integer id) {
        this.id = id;
    }

    //实现Cloneable接口中的clone()方法
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Student [id=" + id + "]";
    }

    public static void main(String[] args) throws Exception {

        System.out.println("-----------使用new关键字创建对象----------------");
        Student stu1 = new Student(123);
        System.out.println(stu1);


        System.out.println("-----------使用Class类的newInstance方法创建对象----------------");
        Student stu2 = Student.class.newInstance();    //对应类必须具有无参构造方法,且只有这一种创建方式
        System.out.println(stu2);


        System.out.println("-----------使用Constructor类的newInstance方法创建对象----------------");
        Constructor<Student> constructor = Student.class.getConstructor(Integer.class);   // 调用有参构造方法
        Student stu3 = constructor.newInstance(123);
        System.out.println(stu3);


        System.out.println("-----------使用Clone方法创建对象----------------");
        Student stu4 = (Student) stu3.clone();
        System.out.println(stu4);


        System.out.println("-----------使用(反)序列化机制创建对象----------------");
        // 写对象
        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("student.bin"));
        output.writeObject(stu4);
        output.close();

        // 读取对象
        ObjectInputStream input = new ObjectInputStream(new FileInputStream("student.bin"));
        Student stu5 = (Student) input.readObject();
        System.out.println(stu5);

    }
}

截图
在这里插入图片描述

2.创建对象的步骤

在这里插入图片描述

1).判断对象对应的类是否加载、链接、初始化

虚拟机遇到一条new指令,首先去检查这个指令的参数能否在Metaspace的常量池中定位到个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化。( 即判断类元信息是否存在)。如果没有,那么在双亲委派模式下,使用当前类加载器以ClassLoader+包名+类名为Key进行查找对应的.class文件。如果没有找到文件,则抛出ClassNotFoundException异常,如果找到,则进行类加载,并生成对应的Class类对象

2).为对象分配内存
首先计算对象占用空间大小,接着在堆中划分一块内存给新对象。如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小。

①内存规整一指针碰撞(当对象创建后,原先指向就对象空间与空间对象空间中间的指针,就会移动到新对象和剩余空闲空间的中间)
②内存不规整一虚拟机维护了一个列表,记录上哪些内存块是可用的,再分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。这种分配方式成为“空闲列表( Free List ) "。

3).处理并发安全问题:
①采用CAS配上失败重试保证更新的原子性
②每个线程预先分配一块TLAB新生代伊甸园区中很小的一块空间,适用于对象实力特别小时,是堆空间中唯一各线程私有的地方

4).初始化分配到的空间
所有实例变量设置默认值,保证对象实例字段在不赋值时可以直接使用。
类变量(静态变量)是在类加载过程的链接期的准备阶段(prepare)赋值的,为类变量分配内存并且设置该类变量的默认初始值,即零值。

5).设置对象的对象头
将对象的所属类(即类的元数据信息)、对象的HashCode和对象的GC信息、 锁信息等数据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现。

6).执行init方法进行初始化(显示初始化,代码块中初始化,构造器初始化)

二、对象的内存布局

在这里插入图片描述
在这里插入图片描述

三、对象的访问定位

在这里插入图片描述
访问方式有两种:1.句柄访问2.直接指针(Hotspot采用)
1.句柄访问
将java堆空间中分配一个为句柄池空间和一个实例池空间,虚拟机栈局部变量表中方法引用指针指向堆空间对象的实例数据的指针和对象的类型数据指针,实例数据的指针指向实力池中的实例数据,类型数据指针则指向方法区中的对象类型数据
在这里插入图片描述
2.直接访问
虚拟机栈局部变量表中方法引用指针指向堆空间中对象的实例数据,对象实例数据里的类型数据指针则指向方法区中的对象类型数据
在这里插入图片描述
3.两种对象访问的优缺点

句柄访问为二次访问,效率低,比较稳定,而对象的直接访问效率高,不稳定

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值