庖丁解牛,洞悉 Java 面向对象的精妙架构

06-01 391阅读

友友们,互三啦!!互三必回!!后台踢踢哦~

更多精彩:个人主页

更多java笔记系列:java学习笔记

赛博算命系列:赛博算命

赛博算命之 ”梅花易数“ 的 “JAVA“ 实现 ——从玄学到科学的探索

赛博算卦之周易六十四卦JAVA实现:六幺算尽天下事,梅花化解天下苦。

庖丁解牛,洞悉 Java 面向对象的精妙架构

文章目录

  • #面向对象的介绍:
  • 一、设计对象并使用
    • 1.类和对象
    • 2.类的几个补充注意事项
    • 3.开发中类的设计
    • 二、封装
      • 1.封装的介绍
      • 2.封装的好处
      • 3.private关键字
      • 三、this关键字
        • 1.成员变量和局部变量
        • 2.举例
          • 代码详细解释:
            • 1. 类的成员变量定义
            • 2. 构造方法中的 `this` 关键字使用
            • 3. `set` 方法中的 `this` 关键字使用
            • 4. `get` 方法中的 `this` 关键字使用
            • 5. `displayInfo` 方法中的 `this` 关键字使用
            • 四、构造方法
              • 1.构造方法的概述
              • 2.构造方法的格式
              • 3.构造方法的作用
              • 4.构造方法的分类
              • 5.构造方法的注意事项
              • 五、标准JavaBean
                • 1.标准的JavaBean类
                • 六、对象内存图
                  • 1.一个对象的内存图
                    • 内存执行顺序解析(基于Java内存模型)
                      • **1. 类加载阶段(方法区)**
                      • **2. 栈内存操作(main方法启动)**
                      • **3. 堆内存分配(对象实例化)**
                      • **4. 对象初始化流程**
                      • **5. 变量关联与操作**
                      • **6. 方法调用(方法区与栈协作)**
                      • **内存操作完整流程总结**
                      • **关键现象解释**
                      • 2.多个对象的内存图
                        • **2.1、执行顺序与内存操作分步解析**
                          • **1. 加载class文件(方法区)**
                          • **2. 声明局部变量(栈内存)**
                          • **3. 堆内存分配(对象空间开辟)**
                          • **4. 默认初始化(堆内存)**
                          • **5. 显示初始化(堆内存)**
                          • **6. 构造方法初始化(堆内存)**
                          • **7. 地址赋值(栈内存)**
                          • **2.2、内存模型与对象独立性的关键验证**
                            • **1. 对象独立性的体现**
                            • **2. 内存操作流程图解**
                            • **2.3、执行流程总结(分阶段)**
                            • **2.4、常见问题解答**
                              • **1. 为什么`System.out.println(s)` 输出地址?**
                              • **2. 显示初始化和构造方法初始化有何区别?**
                              • **3. 如何优化内存使用?**
                              • 3.两个变量指向同一个对象内存图
                                • 3.1、类加载阶段(方法区)
                                • 3.2、栈内存操作(main方法栈帧)
                                • 3.3、堆内存操作(对象关联)
                                • 3.4、最终内存结构
                                • 3.5、输出结果分析
                                • 4.this的内存原理
                                  • 4.1、类加载阶段(方法区核心操作)
                                  • 4.2、对象实例化流程(堆栈协同)
                                  • 4.3、方法调用时的内存隔离(栈帧作用域)
                                  • 4.4、关键差异对比表
                                  • 4.5、技术扩展:`this`的底层实现
                                  • 5.基本数据类型和引用数据类型的区别
                                    • 5.1基本数据类型
                                    • 5.2引用数据类型
                                    • 七、补充知识:成员变量、局部变量区别

                                      #面向对象的介绍:

                                      面向:拿、找

                                      对象:能干活的东西

                                      面向对象编程:拿东西过来做对应的事情

                                      面向对象编程的例子:

                                      import java.util.Random;
                                      import java.util.Scanner;
                                      public class mian {
                                          public static void main(String[] args) {
                                              //面向对象,导入一个随机数
                                              Random r = new Random();
                                              int data = r.nextInt(10)+1;
                                              //面向对象,输入一个随机数
                                              System.out.println(data);
                                              Scanner sc = new Scanner(System.in);
                                              // 面向对象,输出一个数
                                              System.out.println("请输入一个数:");
                                              int a = sc.nextInt();
                                              System.out.println(a);
                                          }
                                      }
                                      

                                      为什么java要采取这种方法来编程呢?

                                      我们在程序之中要干某种事,需要某种工具来完成,这样更符合人类的思维习惯,编程更简单,更好理解。

                                      面向对象的重点学习对象是什么?

                                      学习获取已有对象并使用,学习如何自己设计对象并使用。——面向对象的语法

                                      一、设计对象并使用

                                      1.类和对象

                                      • 类(设计图):是对象共同特征的描述

                                        如何定义类:

                                        public class 类名{
                                            1.成员变量(代表属性,一般是名词)
                                            2.成员方法(代表行为,一般是动词)
                                            3.构造器(后面学习)
                                            4.代码块(后面学习)
                                            5.内部类(后面学习)
                                        }
                                        
                                        public class Phone{
                                            //属性(成员变量)
                                            String brand;
                                            double price; 
                                            public void call(){
                                            }
                                            public void playGame(){
                                            }
                                        }
                                        

                                        如何得到对象?

                                        如何得到类的对象:
                                        类名 对象名= new 类名();
                                        Phone p = new Phone();
                                        
                                        • 对象:是真实存在的具体东西

                                          拿到对象后能做什么?

                                          对象.成员变量;
                                          对象.成员方法(...)
                                          

                                          在JAVA中,必须先设计类,才获得对象

                                          public class phone {
                                              //属性
                                              String name;
                                              double price;
                                              public void call(){
                                                  System.out.println("打电话");
                                              }
                                              public void send(){
                                                  System.out.println("发短信");
                                              }
                                          }
                                          
                                          //测试
                                          public class phoneTest {
                                              public static void main(String[] args) {
                                                  //创建手机对象
                                                  phone p = new phone();
                                                  //给手机对象赋值
                                                  p.name = "小米";
                                                  p.price = 1999;
                                                  //获取手机对象的属性值
                                                  System.out.println(p.name);
                                                  System.out.println(p.price);
                                                  //调用手机对象的方法
                                                  p.call();
                                                  p.send();
                                              }
                                          }
                                          

                                          2.类的几个补充注意事项

                                          • 用来描述一类事物的类,专业叫做:Javabean类。

                                            在javabean类中,是不写main方法的。

                                          • 在以前,编写main方法的类,叫做测试类。

                                            我们可以在测试中创建javabean类的对象并进行赋值调用。

                                            public class 类名 {
                                                1.成员变量(代表属性)
                                                2.成员方法(代表行为)
                                            }
                                            
                                            public class Student {
                                                //属性(成员变量)
                                                String name;
                                                int age;
                                                //行为方法
                                                public void study(){
                                                    System.out.println("好好学习,天天向上");
                                                }
                                                public void doHomework(){
                                                    System.out.println("键盘敲烂,月薪过万");
                                                }
                                            }
                                            
                                            • 类名首字母建议大写,需要见名知意,驼峰模式。

                                            • 一个java文件中可以定义多个class类,且只能一个类是public修饰的类名必须成为代码文件名。

                                              实际开发中建议还是一个文件定义一个class类。

                                            • 成员变量的完整定义格式是:修饰符 数据类型 变量名称=初始化值;一般无需指定初始化值,存在默认值。

                                              int age;
                                              //这里不写初始化值是因为,这里学生的年龄是一个群体的值,没有一个固定的初始化值。
                                              //如果给age赋值,比如是18岁,那就代表者所有的学生年龄都是18岁。
                                              
                                              //类的赋值不是在类里面赋值,而是在创建了对象之后再赋值,这时赋值的时这个特定的对象。
                                              Student stu = new Student();
                                              Stu.name="张三";
                                              Stu.height=187;
                                              

                                              对象的成员变量的默认值规则

                                              数据类型明细默认值
                                              基本类型byte,short,int,long0
                                              基本类型float,double0.0
                                              基本类型booleanfalse
                                              引用类型类、接口、数组、Stringnull
                                              //编写女朋友类,创建女朋友类的对象,给女朋友的属性赋值并调用女朋友类中的方法。自己思考女朋友有哪些属性,有哪些行为?
                                              public class girlFriend {
                                                  public static void main(String[] args) {
                                                      //创建女朋友对象
                                                      girl g = new girl();
                                                      //给女朋友对象赋值
                                                      g.name = "小红";
                                                      g.age = 20;
                                                      g.hobby = "唱歌";
                                                      //获取女朋友对象的属性值
                                                      System.out.println(g.name);
                                                      System.out.println(g.age);
                                                      System.out.println(g.hobby);
                                                      //调用女朋友对象的方法
                                                      g.eat();
                                                      g.sleep();
                                                  }
                                              }
                                              
                                              //这是一个类
                                              public class girl {
                                                  //成员变量(代表属性)
                                                  String name;
                                                  int age;
                                                  String hobby;
                                                  //成员方法(代表行为)
                                                  public void eat(){
                                                      System.out.println("吃饭");
                                                  }
                                                  public void sleep(){
                                                      System.out.println("睡觉");
                                                  }
                                              }
                                              

                                              3.开发中类的设计

                                              先把需求拿过来,先要看这个需求当中有几类事物。每个事物,每类事务都要定义为单独的类,这类事物的名词都可以定义为属性,这类事物的功能,一般是动词,可以定义为行为。

                                              二、封装

                                              1.封装的介绍

                                              封装是面向对象的三大特征:封装、继承、多态

                                              封装的作用:告诉我们,如何正确设计对象的属性和方法。

                                              /**需求:定义一个类描述人
                                              属性:姓名、年龄
                                              行为:吃饭、睡觉*/
                                              public class Person{
                                                  String name;
                                                  int age;
                                                  public void eat(){
                                                      System.out.println("吃饭");
                                                  }
                                                  public void sleep(){
                                                      System.out.println("睡觉");
                                                  }
                                              }
                                              

                                              原则:对象代表什么,就得封装对应的数据,并提供数据对应的行为。

                                              public class Circle {
                                                  double radius;
                                                  public void draw(){
                                                      System.out.println("根据半径"+radius+"画圆");
                                                  }
                                              }
                                              //人画圆,我们通常人为行为主体是人,其实是圆
                                              //例如:人关门,这个门一定是门自己关的,人只是给了作用力,是门自己关上的。
                                              

                                              2.封装的好处

                                              • 对象代表什么,就得封装对应的数据,并提供数据对应的行为
                                              • 降低我们的学习成本,可以少学,少记,或者说压根不用学,不用记对象有哪些方法,有需要时去找就行

                                                3.private关键字

                                                • 是一个权限修饰符

                                                • 可以修饰成员(成员变量和成员方法)

                                                • 被private修饰的成员只能在本类中才能访问

                                                  public class GirlFriend{
                                                      private String name;
                                                      private int age;
                                                      private String gender;
                                                  }
                                                  
                                                  public class leiMing {
                                                      private int age;
                                                      //set(赋值)
                                                      public void setAge(int a){
                                                          if(a120){
                                                              System.out.println("你给的年龄有误");
                                                              return;
                                                          }
                                                          age = a;
                                                      }
                                                      //get(取值)
                                                      public int getAge(){
                                                          return age;
                                                      }
                                                  }
                                                  
                                                • 针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作

                                                • 提供“setXxx(参数)”方法,用于给成员变量复制,方法用public修饰

                                                • 提供“getXxx()”方法,用于获取成员变量的值,方法用public修饰

                                                  为什么要调用set和get呢?

                                                  封装是面向对象编程的四大特性之一,它将数据(成员变量)和操作数据的方法绑定在一起,并隐藏对象的内部实现细节。通过将成员变量声明为 private,外部类无法直接访问和修改这些变量,只能通过类提供的 set 和 get 方法来间接操作。这样可以防止外部代码对数据进行非法或不恰当的修改,保证数据的安全性和完整性。

                                                  三、this关键字

                                                  1.成员变量和局部变量

                                                  public class GirlFriend{
                                                      private int age;//成员变量:方法的外面,类的里面
                                                      public void method(){
                                                          int age = 10;//局部变量:方法的里面
                                                          System.out.println(age);
                                                      }
                                                  }
                                                  

                                                  成员变量和局部变量一致时,采用就近原则

                                                  谁离我近,我就用谁

                                                  public class GirlFriend{
                                                      private int age;//成员变量:方法的外面,类的里面
                                                      public void method(){
                                                          int age = 10;//局部变量:方法的里面
                                                          System.out.println(age);
                                                      }
                                                  }
                                                  //在这里中,最后1个age距离 age=10最近,所以最后一个age用的是10的值
                                                  //假如我想用第一个int ,我们可以在System.out.println(this.age)
                                                  age前加入:this. 这里就可以打破就近原则,选择另一个变量
                                                  

                                                  在 Java 中,当局部变量(比如方法的参数)和类的成员变量重名时,就会产生命名冲突。在这种情况下,如果直接使用变量名,Java 默认会使用局部变量。而 this 关键字的一个重要作用就是用来引用当前对象的成员变量,从而区分局部变量和成员变量。

                                                  2.举例

                                                  下面通过一个简单的示例来详细讲解从引用成员变量方向 this 关键字的用法:

                                                  class Employee {
                                                      // 定义成员变量
                                                      private String name;
                                                      private int age;
                                                      // 构造方法,用于初始化员工信息
                                                      public Employee(String name, int age) {
                                                          // 这里参数名和成员变量名相同,使用 this 引用成员变量
                                                          this.name = name;
                                                          this.age = age;
                                                      }
                                                      // 设置员工姓名的方法
                                                      public void setName(String name) {
                                                          // 使用 this 引用成员变量
                                                          this.name = name;
                                                      }
                                                      // 获取员工姓名的方法
                                                      public String getName() {
                                                          return this.name;
                                                      }
                                                      // 设置员工年龄的方法
                                                      public void setAge(int age) {
                                                          // 使用 this 引用成员变量
                                                          this.age = age;
                                                      }
                                                      // 获取员工年龄的方法
                                                      public int getAge() {
                                                          return this.age;
                                                      }
                                                      // 显示员工信息的方法
                                                      public void displayInfo() {
                                                          System.out.println("姓名: " + this.name + ", 年龄: " + this.age);
                                                      }
                                                  }
                                                  public class ThisKeywordVariableExample {
                                                      public static void main(String[] args) {
                                                          // 创建一个 Employee 对象
                                                          Employee employee = new Employee("李四", 25);
                                                          // 调用 displayInfo 方法显示员工信息
                                                          employee.displayInfo();
                                                          // 调用 setName 和 setAge 方法修改员工信息
                                                          employee.setName("王五");
                                                          employee.setAge(30);
                                                          // 再次调用 displayInfo 方法显示修改后的员工信息
                                                          employee.displayInfo();
                                                      }
                                                  }
                                                  

                                                  代码详细解释:

                                                  1. 类的成员变量定义
                                                  private String name;
                                                  private int age;
                                                  

                                                  这里定义了两个私有成员变量 name 和 age,用于存储员工的姓名和年龄。

                                                  2. 构造方法中的 this 关键字使用
                                                  public Employee(String name, int age) {
                                                      this.name = name;
                                                      this.age = age;
                                                  }
                                                  

                                                  在构造方法中,参数名 name 和 age 与类的成员变量名相同。此时,this.name 表示当前对象的成员变量 name,而直接使用的 name 则是构造方法的参数(局部变量)。通过 this.name = name; 语句,将局部变量 name 的值赋给了当前对象的成员变量 name。同理,this.age = age; 也是将局部变量 age 的值赋给了成员变量 age。

                                                  3. set 方法中的 this 关键字使用
                                                  public void setName(String name) {
                                                      this.name = name;
                                                  }
                                                  public void setAge(int age) {
                                                      this.age = age;
                                                  }
                                                  

                                                  在 setName 和 setAge 方法中,同样存在参数名和成员变量名相同的情况。使用 this 关键字来明确指定要操作的是当前对象的成员变量,避免了与局部变量的混淆。

                                                  4. get 方法中的 this 关键字使用
                                                  public String getName() {
                                                      return this.name;
                                                  }
                                                  public int getAge() {
                                                      return this.age;
                                                  }
                                                  

                                                  在 get 方法中,使用 this.name 和 this.age 来返回当前对象的成员变量的值。虽然在这种情况下,不使用 this 关键字也可以正常返回成员变量的值,因为这里没有局部变量与成员变量重名的问题,但使用 this 可以使代码的意图更加清晰,表明是在访问当前对象的成员变量。

                                                  5. displayInfo 方法中的 this 关键字使用
                                                  public void displayInfo() {
                                                      System.out.println("姓名: " + this.name + ", 年龄: " + this.age);
                                                  }
                                                  

                                                  在 displayInfo 方法中,使用 this.name 和 this.age 来获取当前对象的成员变量的值,并将其输出。

                                                  四、构造方法

                                                  1.构造方法的概述

                                                  构造方法也叫做构造器、构造函数

                                                  2.构造方法的格式

                                                  public class Student{
                                                      修饰符 类名(参数){
                                                          方法体;
                                                      }
                                                  }
                                                  
                                                  public class Student {
                                                      private String name;
                                                      private int age;
                                                      //如果我们自己没有写构造方法
                                                      // 那么编译器会自动生成一个无参构造方法
                                                      public Student() {
                                                          System.out.println("无参构造方法");
                                                      }
                                                      public Student(String name, int age) {
                                                          this.name = name;
                                                          this.age = age; //有参构造方法
                                                      }
                                                      public String getName() {
                                                          return name;
                                                      }
                                                      public void setName(String name) {
                                                          this.name = name;
                                                      }
                                                      public int getAge() {
                                                          return age;
                                                      }
                                                      public void setAge(int age) {
                                                          this.age = age;
                                                      }
                                                  }
                                                  
                                                  public class StudentTest {
                                                      public static void main(String[] args) {
                                                          //创建类的对象
                                                          //调用的空参构造
                                                          //Student s1 = new Student();
                                                          Student s = new Student(name:"张三", age:20);
                                                          System.out.println(s.getName());
                                                          System.out.println(s.getAge());
                                                      }
                                                  }
                                                  

                                                  特点:

                                                  1. 方法名与类名相同,大小写也要一致
                                                  2. 没有返回值类型,连void都没有
                                                  3. 没有具体的返回值(不能由return带回结果数据)

                                                  执行时机:

                                                  1. 创建对象的时候由虚拟机调用,不能手动调用构造方法
                                                  2. 每创建一次对象,就会调用过一次构造方法

                                                  3.构造方法的作用

                                                  在创建对象的时候,由虚拟机自动调用构造方法,作用是给成员变量进行初始化的

                                                  4.构造方法的分类

                                                  public class Student{
                                                      private String name;
                                                      private int age;
                                                      
                                                      public Student(){
                                                       ...//空参构造方法
                                                      }
                                                      
                                                      public Student (String name, int age){
                                                      ....//带全部参数构造方法
                                                      }
                                                  }
                                                  

                                                  无参构造方法:初始化的对象时,成员变量的数据均采用默认值

                                                  有参构造方法:在初始化对象的时候,同时可以为对象进行

                                                  5.构造方法的注意事项

                                                  1. 构造方法的定义
                                                    • 如果没有定义构造方法,系统将给出一个默认的无参数构造方法
                                                    • 如果定义了构造方法,系统将不再提供默认的构造方法
                                                    • 构造方法的重载
                                                      • 带参构造方法,和无参构造方法,两者方法名相同,但是参数不同,这叫做构造方法的重载
                                                      • 推荐的使用方式
                                                        • 无论是否使用,都动手书写无参数构造方法,和带全部参数的构造方法

                                                  五、标准JavaBean

                                                  1.标准的JavaBean类

                                                  1. 类名需要见名知意
                                                  2. 成员变量使用private修饰
                                                  3. 提供至少两个构造方法
                                                    • 无参构造方法
                                                    • 带全部参数的构造方法
                                                    • 成员方法
                                                      • 提供每一个成员变量对应的setXxx()/getXxx()
                                                      • 如果还有其他行为,也需要写上
                                                  举例子:
                                                  根据一个登录界面写一个JavaBean类
                                                  public class User {
                                                      //属性
                                                      private String username;
                                                      private String password;
                                                      private String email;
                                                      private String gender;
                                                      private int age;
                                                      //构造方法
                                                      //无参构造
                                                      public User() {
                                                      }
                                                      //有参构造
                                                      public User(String username, String password, String email, String gender, int age) {
                                                          this.username = username;
                                                          this.password = password;
                                                          this.email = email;
                                                          this.gender = gender;
                                                          this.age = age;
                                                      }
                                                      //方法
                                                      //set和get方法
                                                      public String getUsername() {
                                                          return username;
                                                      }
                                                      public void setUsername(String username) {
                                                          this.username = username;
                                                      }
                                                      public String getPassword() {
                                                          return password;
                                                      }
                                                      public void setPassword(String password) {
                                                          this.password = password;
                                                      }
                                                      public String getEmail() {
                                                          return email;
                                                      }
                                                      public void setEmail(String email) {
                                                          this.email = email;
                                                      }
                                                      public String getGender() {
                                                          return gender;
                                                      }
                                                      public void setGender(String gender) {
                                                          this.gender = gender;
                                                      }
                                                      public int getAge() {
                                                          return age;
                                                      }
                                                      public void setAge(int age) {
                                                          this.age = age;
                                                      }
                                                      
                                                  }
                                                  
                                                  我们再写一个javabean中会遇到一个问题:
                                                  这样写纯体力活啊!没事的没事的!我们有快捷键:
                                                      
                                                  方法一:
                                                      
                                                  alt+insert 或 alt+insert+Fn
                                                  alt+insert 第一个是构造函数,点击无选择生成的是空参 ,全选ok生成的是有参数的构造函数
                                                  alt+insert 点击setter和geteer,全选生成的是set和get
                                                      
                                                  方法二:
                                                      
                                                  下载插件pdg,下载完成后点击空白处就会出现。然后点击Ptg To JavaBean
                                                  

                                                  六、对象内存图

                                                  1.一个对象的内存图

                                                  Student s = new Student();
                                                  
                                                  1. 加载class文件
                                                  2. 申明局部变量
                                                  3. 在堆中开辟一个空间
                                                  4. 默认初始化
                                                  5. 显示初始化
                                                  6. 构造方法初始化
                                                  7. 将堆中空间的地址值赋值给左边的局部变量
                                                  举例:
                                                  public class Student{
                                                      String name;
                                                      int age;
                                                      
                                                      public void study(){
                                                          System.out.println("好好学习")
                                                      }
                                                  }
                                                  
                                                  public class TestStudent{
                                                      public static void main(String [] args){
                                                          Student s= new Student();
                                                          System.out.println(s);
                                                          System.out.println(s.name+"...."+s.age);
                                                          s.name = "阿强";
                                                          s.age = 23;
                                                          System.out.println(s.name+"..."+s.age);
                                                          s.study();
                                                      }
                                                  }
                                                  

                                                  庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                  解析:

                                                  内存执行顺序解析(基于Java内存模型)


                                                  1. 类加载阶段(方法区)
                                                  • 加载class文件

                                                    JVM将

                                                    Student.class
                                                    

                                                    TestStudent.class
                                                    

                                                    加载到方法区,存储类结构信息(字段、方法签名、常量池等)。

                                                    • Student类包含字段name(String)、age(int)和方法study()。
                                                    • TestStudent类包含main()方法入口。
                                                      2. 栈内存操作(main方法启动)
                                                      • 声明局部变量

                                                        执行main()时,在栈内存中创建main方法的栈帧,声明局部变量s(此时s未指向任何对象,值为null)。


                                                        3. 堆内存分配(对象实例化)
                                                        • 在堆中开辟空间

                                                          执行new Student()时,在堆内存中为Student对象分配空间,内存大小由字段类型决定(String引用 + int值)。


                                                          4. 对象初始化流程
                                                          • 默认初始化

                                                            对象字段赋默认值:

                                                            • name → null(引用类型默认值)
                                                            • age → 0(基本类型默认值)。
                                                            • 显示初始化(本例中无)

                                                              如果类中字段有显式赋值(如String name = "默认";),此时会执行。但示例代码未定义,此步骤跳过。

                                                            • 构造方法初始化(本例中无)

                                                              如果存在构造方法(如public Student() { age = 18; }),会通过构造器赋值。示例代码未定义构造方法,此步骤跳过。


                                                              5. 变量关联与操作
                                                              • 地址赋值给局部变量

                                                                堆中对象地址赋值给栈帧中的

                                                                s
                                                                

                                                                变量,完成引用关联。

                                                                • 执行Student s = new Student();后,s指向堆内存中的对象。
                                                                • 对象字段修改

                                                                  后续代码通过s.name = "阿强";和s.age = 23;直接修改堆中对象的字段值,无需重新初始化。


                                                                  6. 方法调用(方法区与栈协作)
                                                                  • 执行s.study()
                                                                    • 从方法区加载study()的字节码指令。
                                                                    • 在栈中创建study()方法的栈帧,执行System.out.println(" 好好学习")(注:用户代码此处缺少分号,实际会编译报错)。

                                                                      内存操作完整流程总结

                                                                      步骤操作内容内存区域示例代码体现
                                                                      1加载类信息方法区Student和TestStudent类加载
                                                                      2声明局部变量s栈内存Student s;
                                                                      3堆中分配对象空间堆内存new Student()
                                                                      4字段默认初始化(null/0)堆内存s.name 和s.age 初始值
                                                                      5显式/构造初始化(无)-代码未定义相关逻辑
                                                                      6对象地址赋值给s栈内存s = new Student();
                                                                      7修改字段值堆内存s.name = "阿强";等操作

                                                                      关键现象解释

                                                                      • System.out.println(s) 输出哈希值

                                                                        因打印对象时默认调用toString(),而Student未重写该方法,输出格式为类名@哈希值。

                                                                      • 字段值修改的可见性

                                                                        直接通过引用s修改堆中对象字段,所有指向该对象的引用均会看到更新后的值。

                                                                      • 编译隐患

                                                                        study()方法中System.out.println(" 好好学习")缺少分号,实际运行前会因语法错误中断。

                                                                        2.多个对象的内存图

                                                                        举例:
                                                                        public class Student{
                                                                            String name;
                                                                            int age;
                                                                            
                                                                            public void study(){
                                                                                System.out.println("好好学习");
                                                                            }
                                                                        }
                                                                        
                                                                        public class TestStudent{
                                                                            public static void main(String [] args){
                                                                                Student s= new Student();
                                                                                System.out.println(s);
                                                                                s.name = "阿强";
                                                                                s.age = 23;
                                                                                System.out.println(s.name+"..."+s.age);
                                                                                s.study();
                                                                                
                                                                                Student s2= new Student();
                                                                                System.out.println(s2);
                                                                                s2.name = "阿珍";
                                                                                s2.age = 24;
                                                                                System.out.println(s2.name+"..."+s2.age);
                                                                                s2.study();
                                                                            }
                                                                        }
                                                                        

                                                                        庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                                        第二次在创建对象时。class文件不需要再加载一次

                                                                        庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                                        解析:

                                                                        2.1、执行顺序与内存操作分步解析

                                                                        1. 加载class文件(方法区)
                                                                        • 触发条件:首次使用Student类时。
                                                                        • 操作内容:
                                                                          • 将Student.class 加载到方法区,存储类结构(字段name、age和方法study()的定义)。
                                                                          • 将TestStudent.class 加载到方法区,存储main()方法入口。
                                                                            2. 声明局部变量(栈内存)
                                                                            • 操作内容:
                                                                              • 执行main()方法时,在栈内存创建main方法的栈帧。
                                                                              • 声明局部变量s和s2(初始值均为null)。
                                                                                3. 堆内存分配(对象空间开辟)
                                                                                • 操作内容:
                                                                                  • new Student()触发堆内存分配,根据类结构计算对象大小(String引用 + int值)。
                                                                                  • 示例:
                                                                                    • s = new Student() → 堆地址0x001。
                                                                                    • s2 = new Student() → 堆地址0x002(独立空间)。
                                                                                      4. 默认初始化(堆内存)
                                                                                      • 操作内容:
                                                                                        • 对象字段赋默认值:
                                                                                          • name → null(引用类型默认值)。
                                                                                          • age → 0(基本类型默认值)。
                                                                                          • 示例:
                                                                                            • s的初始状态:name=null, age=0。
                                                                                            • s2的初始状态:name=null, age=0。
                                                                                              5. 显示初始化(堆内存)
                                                                                              • 触发条件:类中显式赋值的字段(如String name = "默认")。
                                                                                              • 当前代码:
                                                                                                • Student类未定义显式赋值字段,跳过此步骤。
                                                                                                  6. 构造方法初始化(堆内存)
                                                                                                  • 触发条件:存在自定义构造方法(如public Student() { ... })。
                                                                                                  • 当前代码:
                                                                                                    • Student类未定义构造方法,使用默认无参构造器,跳过此步骤。
                                                                                                      7. 地址赋值(栈内存)
                                                                                                      • 操作内容:
                                                                                                        • 将堆内存地址赋值给栈中的局部变量。
                                                                                                        • 示例:
                                                                                                          • s = 0x001(指向第一个对象)。
                                                                                                          • s2 = 0x002(指向第二个对象)。

                                                                                                            2.2、内存模型与对象独立性的关键验证

                                                                                                            1. 对象独立性的体现
                                                                                                            对象堆地址字段修改后的值
                                                                                                            s0x001name="阿强", age=23
                                                                                                            s20x002name="阿珍", age=24
                                                                                                            • 验证逻辑:
                                                                                                              • s和s2指向不同堆地址,修改其中一个对象的字段不会影响另一个对象。
                                                                                                              • System.out.println(s == s2) → 输出false。
                                                                                                                2. 内存操作流程图解

                                                                                                                庖丁解牛,洞悉 Java 面向对象的精妙架构


                                                                                                                2.3、执行流程总结(分阶段)

                                                                                                                阶段操作内容内存区域
                                                                                                                类加载加载Student和TestStudent类信息方法区
                                                                                                                栈帧创建声明s和s2(初始null)栈内存
                                                                                                                堆内存分配为s和s2分配独立空间堆内存
                                                                                                                对象初始化默认初始化 → 显式赋值(用户代码修改)堆内存
                                                                                                                方法调用study()从方法区加载逻辑到栈执行栈内存

                                                                                                                2.4、常见问题解答

                                                                                                                1. 为什么System.out.println(s) 输出地址?
                                                                                                                • 原因:未重写toString()方法,默认调用Object.toString() ,格式为类名@哈希值。
                                                                                                                  2. 显示初始化和构造方法初始化有何区别?
                                                                                                                  • 显示初始化:直接在类中赋值字段(如String name = "张三"),编译时自动插入到构造方法中。
                                                                                                                  • 构造方法初始化:通过自定义构造器赋值(优先级高于显示初始化)。
                                                                                                                    3. 如何优化内存使用?
                                                                                                                    • 复用对象:避免频繁new对象(尤其循环中)。
                                                                                                                    • 垃圾回收:main()结束后,s和s2成为垃圾对象,由GC自动回收。

                                                                                                                      附:修正后的代码输出示例

                                                                                                                      Student@1b6d3586  
                                                                                                                      阿强...23  
                                                                                                                      好好学习  
                                                                                                                      Student@4554617c  
                                                                                                                      阿珍...24  
                                                                                                                      好好学习  
                                                                                                                      

                                                                                                                      3.两个变量指向同一个对象内存图

                                                                                                                      举例:
                                                                                                                      public class Student{
                                                                                                                          String name;
                                                                                                                          int age;
                                                                                                                          
                                                                                                                          public void study(){
                                                                                                                              System.out.println("好好学习");
                                                                                                                          }
                                                                                                                      }
                                                                                                                      
                                                                                                                      public class TestStudent{
                                                                                                                          public static void main(String [] args){
                                                                                                                              Student s= new Student();
                                                                                                                              s.name = "阿强";
                                                                                                                          
                                                                                                                              Student s2= s;
                                                                                                                              s2.name = "阿珍";
                                                                                                                              System.out.println(s.name+"..."+s2.name);
                                                                                                                          }
                                                                                                                      }
                                                                                                                      

                                                                                                                      庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                                                                                      3.1、类加载阶段(方法区)

                                                                                                                      1. 加载TestStudent.class

                                                                                                                        当JVM启动时,首先将TestStudent.class 加载到方法区,存储类结构信息(成员方法、字段描述等)

                                                                                                                      2. 加载Student.class

                                                                                                                        执行new Student()时触发类加载机制,将Student.class 加载到方法区,包含name、age字段和study()方法元数据


                                                                                                                      3.2、栈内存操作(main方法栈帧)

                                                                                                                      1. 声明局部变量

                                                                                                                        在main方法栈帧中创建引用变量s(地址未初始化)和s2(此时两者均为null)

                                                                                                                      2. 对象创建指令

                                                                                                                        new Student()操作码触发堆内存分配,此时:

                                                                                                                        • 在堆中生成对象内存空间(包含对象头 + String name + int age)
                                                                                                                        • 默认初始化:name=null,age=0(基本类型和引用类型的零值初始化)
                                                                                                                        • 显式初始化:由于Student类没有直接赋值的字段(如String name = "默认名"),此阶段跳过
                                                                                                                        • 构造方法执行

                                                                                                                          若存在构造方法(本案例未定义),会通过invokespecial指令调用方法完成初始化


                                                                                                                      3.3、堆内存操作(对象关联)

                                                                                                                      1. 地址赋值

                                                                                                                        将堆中Student对象地址赋值给栈帧中的s变量(完成s = new Student())

                                                                                                                      2. 引用传递

                                                                                                                        s2 = s操作使s2指向堆中同一个对象(此时两个引用共享对象数据)

                                                                                                                      3. 字段修改

                                                                                                                        通过s2.name = "阿珍"修改堆内存对象数据,此时s.name 同步变化(引用指向同一实体)


                                                                                                                      3.4、最终内存结构

                                                                                                                      内存区域存储内容
                                                                                                                      方法区TestStudent类字节码、Student类元数据(包含study()方法代码)
                                                                                                                      堆内存Student对象实例(name=“阿珍”, age=0)
                                                                                                                      栈内存main方法栈帧:s=0x100(指向堆对象), s2=0x100(与s同地址)

                                                                                                                      3.5、输出结果分析

                                                                                                                      System.out.println(s.name+"..."+s2.name)

                                                                                                                      → 输出阿珍...阿珍(s与s2引用同一对象,堆内数据修改对所有引用可见)

                                                                                                                      关键理解点:引用类型变量的赋值操作传递的是对象地址值,而非创建新对象。这种特性是Java对象共享机制的核心体现。

                                                                                                                      4.this的内存原理

                                                                                                                      public class Student{
                                                                                                                          private int age;
                                                                                                                          public void method(){
                                                                                                                              int age=10;
                                                                                                                              System.out.println(age);//10
                                                                                                                              System.out.println(this.age);//成员变量的值 0
                                                                                                                          }
                                                                                                                      }
                                                                                                                      

                                                                                                                      this的作用:区分局部变量和成员变量

                                                                                                                      this的本质:所在方法调用者的地址值

                                                                                                                      public class Student{
                                                                                                                          private int age;
                                                                                                                          public void method(){
                                                                                                                              int age=10;
                                                                                                                              System.out.println(age);//10
                                                                                                                              System.out.println(this.age);//成员变量的值 0
                                                                                                                          }
                                                                                                                      }
                                                                                                                      
                                                                                                                      public class StudentTest{
                                                                                                                          public static void main (String[] args){
                                                                                                                              Student s = new Student();
                                                                                                                              s.method();
                                                                                                                          }
                                                                                                                      }
                                                                                                                      

                                                                                                                      庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                                                                                      4.1、类加载阶段(方法区核心操作)

                                                                                                                      1. 加载StudentTest.class
                                                                                                                        • JVM启动时优先加载含main()的类到方法区
                                                                                                                        • 存储类元数据:静态变量、方法表(含main()入口地址)
                                                                                                                        • 触发Student.class 加载
                                                                                                                          • 当执行new Student()时触发类加载
                                                                                                                          • 方法区新增:
                                                                                                                            • 字段描述表(private int age的访问权限和偏移量)
                                                                                                                            • method()的字节码指令集合
                                                                                                                            • 隐式默认构造器方法(因无自定义构造方法)

                                                                                                                      4.2、对象实例化流程(堆栈协同)

                                                                                                                      步骤内存区域具体行为代码对应
                                                                                                                      3栈内存在main方法栈帧声明局部变量s(初始值null)Student s;
                                                                                                                      4堆内存分配对象空间:对象头(12字节)+ int age(4字节)= 16字节new Student()
                                                                                                                      5堆内存默认初始化:age=0(基本类型零值填充)隐式执行
                                                                                                                      6堆内存构造方法初始化:执行空参数的方法(无实际操作)隐式调用
                                                                                                                      7栈内存将堆地址(如0x7a3f)赋值给s变量s = new...

                                                                                                                      4.3、方法调用时的内存隔离(栈帧作用域)

                                                                                                                      执行s.method() 时发生:

                                                                                                                      1. 新建栈帧:在栈顶创建

                                                                                                                        method()
                                                                                                                        

                                                                                                                        的独立空间,包含:

                                                                                                                        • 隐式参数this(指向堆地址0x7a3f)
                                                                                                                        • 局部变量age=10(存储于栈帧变量表)
                                                                                                                        • 变量访问规则:

                                                                                                                          输出语句内存访问路径结果
                                                                                                                          System.out.println(age)访问栈帧局部变量表10
                                                                                                                          System.out.println(this.age)通过this指针访问堆内存字段0

                                                                                                                      4.4、关键差异对比表

                                                                                                                      特征成员变量this.age局部变量age
                                                                                                                      存储位置堆内存对象内部栈帧局部变量表
                                                                                                                      生命周期与对象共存亡随方法栈帧销毁而消失
                                                                                                                      初始化值默认零值(int=0)必须显式赋值
                                                                                                                      访问方式需通过对象引用直接访问

                                                                                                                      4.5、技术扩展:this的底层实现

                                                                                                                      当调用method()时:

                                                                                                                      1. 字节码层面:

                                                                                                                        java复制aload_0         // 将this引用压入操作数栈(对应堆地址0x7a3f)
                                                                                                                        getfield #2    // 根据字段偏移量读取堆中age值(#2为字段符号引用)
                                                                                                                        
                                                                                                                      2. 内存隔离机制:局部变量age会遮蔽同名的成员变量,必须通过this.显式穿透访问堆数据

                                                                                                                      5.基本数据类型和引用数据类型的区别

                                                                                                                      5.1基本数据类型

                                                                                                                      public class Test{
                                                                                                                          public static void main (String [] args){
                                                                                                                              int a = 10;
                                                                                                                          }
                                                                                                                      }
                                                                                                                      

                                                                                                                      基本数据类型:

                                                                                                                      在变量当中存储的是真实的数据值

                                                                                                                      从内存角度:数据值是存储再自己的空间中

                                                                                                                      特点:赋值给其他变量,也是赋值的真实的值。

                                                                                                                      5.2引用数据类型

                                                                                                                      public class TestStudent{
                                                                                                                          public static void main(String[] args){
                                                                                                                              Student s=new Student;
                                                                                                                          }
                                                                                                                      }
                                                                                                                      

                                                                                                                      引用数据类型:

                                                                                                                      堆中存储的数据类型,也就是new出来的,变量中存储的是地址值。引用:就是使用其他空间中数据的意思。

                                                                                                                      从内存的角度:

                                                                                                                      数据值是存储在其他空间中,自己空间中存储的是地址值

                                                                                                                      特点:

                                                                                                                      赋值给其他变量,赋的地址值。

                                                                                                                      七、补充知识:成员变量、局部变量区别

                                                                                                                      成员变量:类中方法外的变量

                                                                                                                      局部变量:方法中的变量

                                                                                                                      庖丁解牛,洞悉 Java 面向对象的精妙架构

                                                                                                                      区别:

                                                                                                                      区别成员变量局部变量
                                                                                                                      类中位置不同类中,方法外方法内、方法申明上
                                                                                                                      初始化值不同有默认初始化值没有,使用前需要完成赋值
                                                                                                                      内存位置不同堆内存栈内存
                                                                                                                      生命周期不同随着对象的创建而存在,随着对象的消失而消失随着方法的调用而存在,随着方法的运行结束而消失
                                                                                                                      作用域整个类中有效当前方法中有效

                                                                                                                      庖丁解牛,洞悉 Java 面向对象的精妙架构

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码