关于java:new的过程发生了什么看完这一篇就懂了

43次阅读

共计 3890 个字符,预计需要花费 10 分钟才能阅读完成。

在事实世界中,找对象是一门学识,找对象不在于多而在于精

在计算机世界中,面向对象编程 的关键在于是否灵便地使用类,如何设计出一个合乎需要的对象也是也是值得学习和思考的。

那么,面向对象编程 到底是什么?

面向对象编程 中,必定会波及 对象 两个概念。 是什么?对象 是什么,两者有什么关系?

接下来就一 一地来解答这些纳闷吧

类和对象

  • 类,是指将雷同属性的货色放在放在一起,类是一个模板,可能形容一类对象的状态和行为
  • 而对象,就是理论存在某个类中的一个个的个体,所以也被称为实例(instance)。
  • 对象的形象是类,类的具体化就是对象,也就是类的实例就是对象。

在 C 语言中,构造体是数据的汇合,它将数据捆绑在一起,使得咱们能够将这些数据看作是一个整体。而对构造体中的数据 进行操作的函数就写在构造体的内部。

而在面向对象编程中,将示意事物行为的函数也放入了这个整体,就造成了对象的概念。使得这个整体既形容属性,又能形容行为。

所以,面向对象编程是一种将关注点置于 对象 Object自身的程序设计办法,对象的形成因素蕴含 对象的行为及操作,以此根底进行编程。

这种办法使得程序易于复用。OOP 次要应用的 编程技巧 有:继承 封装 多态 三种。

说了这么多,是不是看晕了,没关系,持续往下看。

事实世界中的形象

在现实生活中,能够将人看成一个类,这类称为人类(抽象类)

如果某个男孩想找一个对象(女朋友),那么所有的女孩都是这个男孩选女朋友的范畴,所有的女孩就是一【类】

  • 对象

如果这个时候男孩曾经找到喜爱的对象了,他的女朋友名字叫【林允儿】。那么假如这个名字是惟一的,此时名字叫【林允儿】的这个女孩就是一个对象(小声 bb,其实{她是我老婆 |hē hē hē hē}[狗头])

接下来通过具体的代码来解说一下

// FileName: Person.java
public abstract class Person {

    protected int age;
    protected String name;
    
    public Person(int age,String name) {
        
        this.age = age;
        this.name = name;
        
    }

    public abstract void speak();

    public abstract void sayInfo(Person person);

}

复制代码

在这里,定义了一个 抽象类 - 人 ,在人的这个抽象类外面,蕴含了人的一些 属性 行为 ,代表了人具备的 独特属性

而后,定义了一个 子类 Man 子类 Woman继承 父类 Person, 外面蕴含了独特领有的属性,并减少了性别 sex,而后对办法进行了 重写

// FileName: Man.java
public class Man extends Person {
    private String sex = "man";
    public Man(int age,String name) {super(age,name);
    }
  
    @Override
  
    public void speak() {System.out.println("我的名字是:" + super.name + "n" + "我往年" + super.age + "岁了.");
    };

    @Override    
    
    public void sayInfo(Person person) {System.out.println("我的女朋友是:" + person.name + "n" + "她往年" + person.age + "岁了.");
    }
}
复制代码

// FileName: WoMan.java
public class WoMan extends Person {
    private String sex = "woman";
    public WoMan(int age,String name) {super(age,name);
    }
  
    @Override
  
    public void speak() {System.out.println("我的名字是:" + super.name + "n" + "我往年" + super.age + "岁了.");
    };

    @Override    
    
    public void sayInfo(Person person) {System.out.println("我的男朋友是:" + person.name + "n" + "她往年" + person.age + "岁了.");
    }
}
复制代码

那么,他们的关系就是如下图:

所以,一个类的根本组成为下图:

那么,咱们再来编写下测试代码:

// FileName: TestPerson.java
public class TestPerson {
    /**
     * @param args
     */
    public static void main(String[] args) {Person codevald = new Man(21,"codevald");
        Person lye = new Woman(20,"linyuer");
    
        codevald.speak();
        codevald.sayInfo(lye);
    
        lye.speak();
        lye.sayInfo(codevald);
    
      }
}
复制代码

运行后果:

接下来,是最有意思的局部,咱们来剖析下代码中 new 的时候产生了什么。

new 操作的过程

当咱们 new 一个对象的时候 JVM 首先会去找到对应的类元信息,如果找不到意味着类信息还没有被加载,所以在对象创立的时候也可能会触发类的加载操作。当类元信息被加载之后,咱们就能够通过类元信息来确定对象信息和须要申请的内存大小。

对象创立的流程

1. 构建对象

首先 main 线程会在栈中申请一个属于本人的栈空间,而后咱们调用 main 办法的时候,会生成一个 main 办法的栈帧,而后执行 new Man(),这里会依据 Man 类的元信息先确定对象的大小,而后在 JVM 堆里申请一块内存区域并构建对象,同时对 Man 对象成员变量信息 并赋予默认值(在这里会波及多态,在内存中的分配情况有机会再解释解释)。

2. 初始化对象

这一步会执行对象外部的 init 办法,初始化成员变量值,即执行对象的构造方法(这里调用父类的构造方法进行赋值),构造方法执行完,此时的 age = 21,name = “codevald”。

3. 援用对象

对象实例化实现之后,再把栈中的 Person 对象援用地址指向 Man 对象在堆内存中的地址

4. 持续结构、初始化,援用对象对象

这一步和下面三个步骤一样,就不具体说了 附上图

5. 调用办法

调用 speak()办法的时候,会先找到 Person 对象(codevald)中的援用地址,找到真正的在堆内存中的Man 对象,执行 speak()办法,执行的时候,会调用父类中的成员变量,所以会找到堆内存中的父对象的成员变量(name 和 age),加载进来,进行输入

我的名字是: codevald 我往年 21 岁了.

调用 sayInfo()办法的时候,一样先找到对象(codevald)中的援用地址,找到真正的在堆内存中的 Man 对象,执行 sayInfo()办法,执行的时候,会找到 Person 对象(linyuner)的地址,即指向堆内存中的 Woman 对象,找到父类外面的成员变量(name 和 age),进行输入

我的女朋友是:linyuer 她往年 20 岁了.

上面的代码的执行过程同理,就留给小伙伴们自行去剖析啦~

附上 TestPerson 的字节码文件,感兴趣的小伙伴能够自行查看进行剖析

Compiled from "TestPerson.java"
public class person.TestPerson {public person.TestPerson();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class person/Man
       3: dup
       4: bipush        21
       6: ldc           #9                  // String codevald
       8: invokespecial #11                 // Method person/Man."<init>":(ILjava/lang/String;)V
      11: astore_1
      12: new           #14                 // class person/Woman
      15: dup
      16: bipush        20
      18: ldc           #16                 // String linyuer
      20: invokespecial #18                 // Method person/Woman."<init>":(ILjava/lang/String;)V
      23: astore_2
      24: aload_1
      25: invokevirtual #19                 // Method person/Person.speak:()V
      28: aload_1
      29: aload_2
      30: invokevirtual #24                 // Method person/Person.sayInfo:(Lperson/Person;)V
      33: aload_2
      34: invokevirtual #19                 // Method person/Person.speak:()V
      37: aload_2
      38: aload_1
      39: invokevirtual #24                 // Method person/Person.sayInfo:(Lperson/Person;)V
      42: return
}
复制代码

学无止境,咱们已经善于的正在被淘汰,不善于的却是依然存在。最根底的往往是最难的,而往往也是最重要的,平时重视根底的积攒,学会去剖析底层的执行过程,才是学习中最应该把握的技能,心愿这篇答复能帮到正在寻找这个问题的答案的你~

参考:《2020 最新 Java 根底精讲视频教程和学习路线!》

链接:https://juejin.cn/post/692241…

正文完
 0