ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java笔记 —— 创建对象的过程(类加载,具体的初始化赋值过程)

2021-10-31 12:01:43  阅读:144  来源: 互联网

标签:初始化 Java name 静态 age 创建对象 int public 变量


package test1.demo;
class Person{
    String name;
    int age;
    static String nationality;
    public Person(){}
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public Person(String name,int age,String nationality){
        this.name = name;
        this.age = age;
        Person.nationality = nationality;
    }
    public void show(){
        System.out.println(name+"--"+age+"--"+nationality);
    }
}
public class PersonDemo {
    public static void main(String[] args) {
        Person p1 = new Person("张",12,"中国");
        p1.show();

        Person p2 = new Person("陈",14,"美国");
        p2.show();

        Person p3 = new Person("周",16,"日本");
        p3.show();

        p3.nationality = "法国";
        p1.show();
        p2.show();
        p3.show();
    }
}

针对这段代码,来说一下具体的创建对象的过程

  1. 首先是将类加载到方法区的class内容区,这里有两个类Person.class和PersonDemo.class,会被加载到class内容区。
    当运行程序的时候,需要用到一个类,会先到方法区查找class信息,如果找到了就拿来用。如果没找到,就会像上面这样,将class类文件加载到方法区里面。

具体的加载类的时机,不完整的说可以分为以下两种(其余的情况比较复杂,这里不说):
(1)遇到new关键字的时候,将需要将创建对象的类加载初始化
(2)Java虚拟机启动的时候,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类

满足这些时机时,就会触发这一步,将 .class文件读入内存

  1. 然后是将类的静态成员变量和静态成员方法,加载到方法区的静态区里面
    (1)把.class文件中的所有静态内容加载到方法区下的静态区域内
    (2)静态内容加载完成之后,对所有的静态变量进行初始化,初始化的顺序是
    默认初始化 ——> 显示初始化 ——> 静态代码块
    默认初始化完成后才会进行显式初始化,显式初始化完成后才是静态代码块
    具体的初始化过程与含义往下看

  2. 将类的非静态变量和非静态方法加载到方法区的非静态区域内,这个方法包括构造方法。

2、3步的顺序可以记为:在.class加载到方法区时,先加载父类再加载子类;先加载静态内容,再加载非静态内容
到这里为止,整个类的加载就完成了。

.class文件读入内存,让类加载完之后会生成一个Class类型对象,这个对象会包含类的数据结构,包含所有信息(比如类名,方法,变量等)
这个Class对象用来创建这个类的所有对象(一个类只能有一个Class对象)

  1. 程序开始时,先将main方法加载到栈里面,然后在栈内存中开辟一个新的空间,用来存放新建的引用变量,比如Person p1,这里并不是新建了一个对象,而是新建了一个变量用来指向堆内存中的对象。

  2. 直到遇到new关键字的时候,才真的在堆内存中划分一块空间用来存储对象。
    (1)使用new关键字创建你对象时,会先在堆内存中开辟一块空间。
    (2)给开辟的空间分配一个地址,比如说0x001
    (3)把对象的所有非静态成员变量加载到所开辟的空间下,加载完非静态变量后还有
    空间还有一个静态标记,用来指向方法区中的类的静态变量的地址(一个类的所有对象共享这个类的静态变量)
    空间还会有一个方法标记,指向这个对象所在类的方法在方法区中的地址
    (4)非静态成员变量加载到空间后会默认初始化(默认初始化的默认值:数字为 0,字符为 null,布尔为 false,而所有引用被设置成 null)
    然后调用构造方法,构造方法会被调用栈里面执行,入栈执行时,分为两部分:
    一、先执行构造函数中的隐式三步,三步分别为
    ▶ 1. 执行super()语句(即先初始化父类的构造方法)
    ▶ 2. 对开辟空间下的所有非静态成员变量进行显示初始化
    ▶ 3. 执行构造代码块
    二、执行构造方法中的代码
    一般来说,成员变量最后的值都是调用构造函数时传进去的值,也就是第二步“执行构造方法中的代码”

  3. 对象调用方法时,根据方法标记到方法区中找到方法,然后方法入栈。方法调用完后就会被清除。

  4. 之后的show方法中需要调用对象的成员变量的时候,先根据栈里面的引用变量找到堆内存中的对象空间,然后发现空间里面只有两个实例对象name和age,没有静态变量,此时就会根据静态标记到方法区去找。找到后返回。

  5. 最后还修改了一下静态变量,根据这个路径找到静态变量:引用变量——>堆内存空间——>方法区——>静态变量,修改静态变量后,之前几个对象的静态标记依旧指向的是这个地址。所以修改了静态变量后,所有对象的静态变量结果都会改变。而实例变量属于对象所有,一个对象改变自己的实例变量不会影响到其他的实例对象。

  6. 所有语句结束后,main方法出栈,程序运行完毕

总结一下,对象里面的实例属性赋值过程:

默认初始化(null,0)——> 显示初始化(name=“zhang”,age=16)——> 构造代码块 ——> 构造方法

默认初始化
package review;

class Demo1{
    //默认初始化
    public String name;
    public int age;

    //构造方法
    public Demo1(){}

    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class gouzaoDemo1 {
    public static void main(String[] args) {
        Demo1 d = new Demo1();
        System.out.println(d.toString());
    }
}

结果为
在这里插入图片描述

显式初始化,构造代码块,构造方法
package review;

class Demo{
    //显式初始化
    public String name = "zhang";
    public int age = 16;
    //构造代码块
    {
        name = "cao";
        age = 12;
    }
    //构造方法
    public Demo(){}
    public Demo(String name , int age){
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Demo{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class gouzaoDemo {
    public static void main(String[] args) {
        Demo d1 = new Demo();
        System.out.println(d1.toString());

        Demo d2 = new Demo("chen",20);
        System.out.println(d2.toString());

    }
}

结果为
在这里插入图片描述

顺带提一下,理解了对象创建过程后再来看这一段代码
package test1;

public class VariableDemo {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        change(a,b);
        System.out.println(a+"--"+b);
    }

    public static void change(int a,int b){
        a = 3;
        b = 4;
    }
}

在这里插入图片描述
因为当a和b是非静态变量的时候,方法内部使用的是新建的局部变量,返回值类型是void,所以局部变量的生命周期会随着方法的调用结束而结束,不会影响到外面的变量。

package test1;

public class VariableDemo {
    static int a = 1;
    static int b = 2;
    public static void main(String[] args) {
        change();
        System.out.println(a+"--"+b);
    }

    public static void change(){
        a = 3;
        b = 4;
    }
}

在这里插入图片描述
调用静态变量的时候,会直接修改方法区里面的静态变量的值,所以外面的静态变量的值也会受到影响。

再拓展一下:
package test1;

import java.util.Arrays;

public class VariableDemo1 {
    public static void main(String[] args) {
        int a = 5;
        int b = 10;
        change(a,b);
        System.out.println(a+"---"+b);
        
        int[] arr = {1,2,3,4,5};
        changeArr(arr);
        System.out.println(Arrays.toString(arr));

    }

    public static void change(int a,int b){
        a = 20;
        b = 30;
    }

    public static void changeArr(int[] arr){
        for(int i=0;i<arr.length;i++){
            if(arr[i]%2==0){
                arr[i] += 10;
            }
        }
    }
}

在这里插入图片描述
会发现都是void类型的方法,change方法没有改变a,b的值,但是changeArr方法改变了arr数组的值

这是因为基本数据类型作为参数传递的时候,传递的是具体的值,本身变量里面的值不参与运行,不会发生变化。基本数据类型的值被调入栈内存中进行运行,方法结束后会随着方法一起消失。栈内存中放着的是局部变量,而变量本身的实体在堆内存中,只在栈里面修改不会影响到堆内存,除非修改void类型,让方法有返回值。

而int[] arr不是基本数据类型,是引用数据类型。引用数据类型作为参数传递的时候,传递的是地址值,所以在方法里面改变的是实际空间里面的值,因此会影响到外面的数据的值。引用数据类型会在堆内存中开辟空间,并执行修改。

标签:初始化,Java,name,静态,age,创建对象,int,public,变量
来源: https://blog.csdn.net/qq_44823756/article/details/121061652

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有