【Java】——java创建对象的过程(内存角度分析)

java对象的创建包含两个过程:类的初始化和实例化。
1、类的初始化过程
加载——>链接 (准备》验证》引用) ——>初始化——>使用——>卸载
类的加载过程(当第一次使用某个类的时候才去加载相应类型)
加载:用类加载器在指定的路径上加载对应的class文件(加载class对象 类的所有信息)
(1)通过一个类的全限定名来获取其定义的二进制字节流

(2)将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构

(3)在堆中生成一个代表这个类的Class对象,作为方法区中这些数据的访问入口。

链接:(准备 验证 引用)验证上面的字节码文件是否能够在当前的jvm上运行;给静态成员开辟内存;它如果有基类,重复上面的步骤加载基类;

(1)类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中,

(2)这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值。
注意,在上面value是被static所修饰的准备阶段之后是0,但是如果同时被final和static修饰准备阶段之后就是1了。我们可以理解为static final在编译器就将结果放入调用它的类的常量池中了。

初始化:.给static静态成员进行初始化工作
这是类加载机制的最后一步,在这个阶段,java程序代码才开始真正执行。我们知道,在准备阶段已经为类变量赋过一次值。在初始化阶端,程序员可以根据自己的需求来赋值了。一句话描述这个阶段就是执行类构造器< clinit >()方法的过程。
在初始化阶段,主要为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
①声明类变量时指定初始值
②使用静态代码块为类变量指定初始值
使用
卸载

2、类的加载顺序:
静态变量>静态块>实例变量>实例块>构造函数

public classlTest {
   //静态变量
    public static String staticField = "静态变量";
   //变量 
    public String field = "普通变量";
   // 静态块
    static {
        System.out.println( staticField );
        System.out.println( "静态块" );
    }
   // 初始化块
    {
        System.out.println( field );
        System.out.println( "初始化块" );
    }
   // 构造方法
    public InitialOrderTest(){
        System.out.println( "构造函数" );
    }

    public static void main( String[] args ){
        new InitialOrderTest();
    }
}
//打印结果:
//静态变量
//静态块
//普通变量
//初始化块
//构造函数

3、创建对象的几种方式
实对象的初始化就是在创建对象的时候由jvm完成的。对于创建对象,主要是研究创建对象的几种方式。这里给出6种方式:
1、使用new关键字

2、Class对象的newInstance()方法

public static void main(String[] args) throws Exception {
   String className = "com.bean.Test";
   Class clasz = Class.forName(className);
   Test t = (Test) clasz.newInstance();
}

3、构造函数对象的newInstance()方法

public static void main(String[] args) throws Exception {
  Constructor<Test> constructor;
  try {
       constructor = Test.class.getConstructor();
      Test t = constructor.newInstance();
  } catch (Exception){
       e.printStackTrace();
  }
}

4、对象反序列化

public static void main(String[] args) throws Exception {
    String filePath = "sample.txt";//序列化的路径
    Test t1 = new Test("java的架构师技术栈");
    try {
       //t1开始序列化
       FileOutputStream fileOutputStream = new FileOutputStream(filePath);
       ObjectOutputStream outputStream = new ObjectOutputStream(fileOutputStream);
       outputStream.writeObject(t1);
       outputStream.flush();
       outputStream.close();
//t2开始反序列化
       FileInputStream fileInputStream = new FileInputStream(filePath);
       ObjectInputStream inputStream = new ObjectInputStream(fileInputStream);
       Test t2 = (Test) inputStream.readObject();
       inputStream.close();
       System.out.println(t2.getName());
    } catch (Exception ee) {
       ee.printStackTrace();
    }
}

5、Object对象的clone()方法

public static void main(String[] args) throws Exception {
   Test t1 = new Test("java的架构师技术栈");
   Test t2 = (Test) t1.clone();
   System.out.println(t2.getName());
}

6、使用Unsafe类创建对象
unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的,所以这里不再给出它的代码示例。
4、总述
我们想要创建一个对象。基本上就是java虚拟机分配内存的过程。因此我们可以先回顾一下java程序的执行过程。

public class Person{
    int age;
    String name;
    public void pp() {
        System.out.println("真漂亮");
    }
}
public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "婷小花";
        person.age = 18;
        person.walk();
    }
}

第一步,JVM去方法区寻找Test类的代码信息,如果有直接调用,没有的话使用类的加载机制把类加载进来。同时把静态变量、静态方法、常量加载进来。这里加载的是(“婷小花”);这是因为字符串是常量,age中的18是基本类型。
第二步,jvm进入main方法,看到Person person=new Person()。首先分析Person这个类,同样的寻找Person类的代码信息,有就加载,没有的话类加载机制加载进来。同时也加载静态变量、静态方法、常量(“真漂亮”)。
第三步,jvm接下来看到了person,person在main方法内部,因而是局部变量,存放在栈空间中。
第四步,jvm接下来看到了new Person()。new出的对象(实例),存放在堆空间中。
第五步,jvm接下来看到了“=”,把new Person的地址告诉person变量,person通过四字节的地址(十六进制),引用该实例。
第六步,jvm看到person.name = “婷小花”;person通过引用new Person实例的name属性,该name属性通过地址指向常量池的"婷小花"。
第七步,jvm看到person.age = 18; person的age属性是基本数据类型,直接赋值。
第八步,jvm看到person.pp(); 调用实例的方法时,并不会在实例对象中生成一个新的方法,而是通过地址指向方法区中类信息的方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值