Java中对象的创建流程

今天通过一例子给大家讲解一下Java中对象的创建流程:

public class Main{
    public static void main(String[] args){
        Person p=new Person("张三",30);
        p.speak();
        System.out.println(Person.country);
        Person.getCountry();
    }
}
class Person{
    public static final String country="China";
    private String name;
    private int age;
    public Person(){}
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public void speak(){
        System.out.println(name+":"+age+":"+country);
    }
    public static void getCountry(){
        System.out.println("Person类的国籍是"+country);
    }
}

上面的代码我们创建了:

  • Person类,实体类,其中包含
    静态成员变量 country,成员变量 name 和 age
    构造函数 Person() 和 Person(String name,int age)
    成员函数 speak()
    静态函数 getCountry()
  • Main类,测试类,其中包含:
    创建一个对象并将地址赋给了变量 p
    调用构造函数 Person(String name,int age)
    调用成员函数 p.speak()
    调用静态函数 Person.getCountry()

从编译运行开始到出结果结束,我会通过图示来描述这个对象的创建流程

  • 首先编译 javac Main.java
    会生成 Main.class 字节码文件 和 Person.class 字节码文件

  • 运行前的准备
    此时,会将我们编译完成后的字节码文件 Main.class 和 Person.class文件加载进JVM,那么具体会加载进那里?
    我们从内存分配角度来分析:
    内存主要分为以下五个区域:
    1.寄存器
    2.本地方法区:我们电脑开机时内存被占%几十,就是系统的运行代码先加载进来,具体就是主要临时存储OS的可执行代码。
    3.方法区:主要临时存储我们的应用程序计算机里(如Windows.exe)的可执行代码,Java所写代码就是应用软件,所以.class文件都会被加载进方法区
    4.栈:随着函数的进栈和弹栈,主要运行函数
    5.堆:对象堆,主要存储对象数据

  • 方法区
    方法区分为(static)静态方法区和非静态方法区(简称方法区)
    静态方法区 主要存放 静态变量 静态函数
    非静态方法区主要存放 构造函数 成员函数 成员变量
    里面不仅仅只有函数,也有字段(变量),比如在Person类所属空间里,他有一个static country 静态变量

  • 开始运行 java Main
    让虚拟机在静态方法区中的Main所属空间里找主函数main()
    java Main 就是在Main类所属空间中去找静态主main(),所以 java Person 不行,因为没有主函数。

  • 主函数main()进栈

  • 然后执行main(),按流程首先看赋值号右边,在堆内存中创建了一个对象
    对象根据类中的成员变量的描述,在对象创建后有了具体的成员变量,类中的描述仅仅只是代表有这个变量,只有在对象有了之后,才会有具体的属性,可以总结为 开空间 给地址 对成员变量进行默认初始化。

  • 构造函数进栈
    1.在这里我们要明确一点,在构造函数刚进栈时,先进行显式初始化,由于的们的Person类中的成员变量没有显式初始化,就执行接下里的针对性初始化,将实参“张三”和“30”的传给形参name 和 age。
    2.为了区分哪个对象调用的这个函数?里面有个this字段,哪个对象的调用 就存哪个对象的地址。
    3.构造函数里有局部变量 name 和 age,对应的是“张三”和“30”;this.name=name,this.age=age,this指的是对象,所以是将“张三”和“30”在常量池中的地址 给了对象中的成员变量name 和 age。

  • 构造函数执行完毕弹栈,将对象的地址赋予左边

  • 左边是在主函数中创建Person类型的p变量空间
    Person p是主函数当中的Person引用类型局部变量p,所以在栈中main()里开辟空间p,然后将上面创建对象地址给了p

  • p.speak(),对象调用成员函数
    1.表示p指的对象去调用speak函数,speak是成员函数,在非静态方法区去找这段代码。
    2.speak()进栈,谁调用的我?同样还存在一个this指的是p的地址,没有局部变量,默认去堆中所指的对象中去找,找到 name 和age 直接打印,System.out.println(name+":"+age+":"+country);
    3.所以,成员函数中寻找变量时,先找局部变量,如果没有局部变量,再在堆中找对象,如果还没有,再去静态方法区中找;
    局部—堆---静态方法区 就近原则
    4.打印完,代码运行完,return 弹栈。

  • Person.country,类名调用静态变量
    1.在调用静态成员时,可以直接去静态方法区中找
    2.Person.xxx Person是因为该区域中有多个类空间 我们得指定一个

  • Person.getCountry(),类名调用静态函数
    1.System.out.println(“Person类的国籍是”+country);
    2.先找局部,没对象不去对象找(没有this),然后直接去静态方法区中找,局部—静态 与堆无关。
    3.为什么静态函数中没有this?
    因为静态方法区的东西是在对象创建之前就有的!所以去找静态方法区的的静态函数没有this

  • 图示

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值