通过前面对 JAVA基础 —— 面向对象 的学习,我们对面向对象有了初步了解。
这篇文章我们旨在通过内存图进一步了解面向对象中的底层逻辑。
目录
一、Java内存分配介绍
注意:
从JDK8开始,取消方法区,新增元空间。把原来方法区的多种功能进行拆分,有的功能放到了堆中,有的功能放到了元空间中。
![]() | ![]() |
二、 一个对象的内存图
Student s = new Student();
- 加载class文件
- 申明局部变量
- 在堆内存中开辟一个空间
- 默认初始化
- 显示初始化
- 构造方法初始化
- 将堆内存中的地址值赋值给左边的局部变量
public class Student {
String name;
int age;
public void study() {
System.out.println("好好学习");
}
}
public class studentTest {
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();
}
}
①加载class文件、申明局部变量、在堆内存中开辟一个空间、构造器和默认值初始化 |
②study()方法进栈、局部变量赋值![]() |
③运算结束,内存出栈、出堆![]() |
④运算结果 |
三、两个对象的内存图
public class Student {
String name;
int age;
public void study() {
System.out.println("好好学习");
}
}
public class studentTest2 {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1);
s1.name = "阿强";
s1.age = 23;
sout(s1.name + "..." + s1.age)
s1.study();
Student s2 = new Student();
System.out.println(s2);
s2.name = "阿珍";
s2.age = 24;
sout(s2.name + "..." + s2.age)
s2.study();
}
}
①字节码文件加载到方法区,main方法临时存储,虚拟机调用main方法加载进栈。加载class文件,左边变量声明空间,右边对象开辟空间,初始化默认值。 |
②获取对象前赋值输出,根据成员方法地址找到study()方法加载进栈。 |
③Study()方法出栈,创建第二个对象。获取对象前赋值输出,根据成员方法地址找到study()方法加载进栈。 注意:这一次 .class字节码是否要再加载一次?不需要,class文件已经加载。 |
④运算结束,内存出栈、出堆![]() |
⑤运算结果: |
四、基本数据类型和引用数据类型
1. 基本数据类型
public class Test{
public static void main(String[] args){
int a = 10;
double b = 20.0;
}
}
只是在栈内存开辟一个小空间,来存储变量类型的变量,与其他内存无关。
2. 引用数据类型
2.1 对象
public class StudentTest{
public static void man(String[] args){
Student s = new Student();
}
}
2.2 数组
public class StudentTest{
public static void main(String[] args){
int[] arr = {1,2,3,4};
}
}
3. 从内存的角度去理解
内容 | 特点 | |
基本数据类型 | 数据值是存储在自己的空间中 | 赋值给其他变量,也是赋的真实的值。 |
引用数据类型 | 数据值是存储在其他空间中,自己空间中存储的是地址值。 | 赋值给其他变量,赋的地址值。 |
五、 this关键字
this关键字作用:区分局部变量和成员变量。
this关键字本质:代表方法调用者的地址值。
public class student{
private int age;
public void method(){
int age = 10;
system.out.println(age);
system.out.println(this.age);
}
}
public class studentTest(){
public static void main(string[] args){
Student s = new Student();
s.method();
}
}
六、 成员变量和局部变量的区别
成员变量:类中方法外的变量
局部变量:方法中的变量
public class Student{
private String name;
private int age;
}
public class Test {
public static void main(String[] args){
int a = 10;
new Student();
}
}
下面表格稍作了解即可:
区别 | 成员变量 | 局部变量 |
类中位置不同 | 类中,方法外 | 方法内、方法申明上 |
初始化值不同 | 有默认初始化值 | 没有,使用之前需要完成赋值 |
内存位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的运行结束而消失 |
作用域 | 整个类中有效 | 当前方法中有效 |