记Java中有关内存的简单认识 一、Java内存划分 二、从数组的内存说起 一个 数组的内存图 两个数组的内存图 三、来看对象的内存 一个对象的内存图 两个对象使用同一个方法时的内存图 两个引用指向同一个对象的内存图 使用对象类型作为方法的参数 使用对象类型作为方法的返回值 四、字符串常量池 五、继承中的内存图

分为五个部分,可以参考这篇笔记简单认识一下:

https://www.cnblogs.com/unleashed/p/13268027.html

方法区 本地方法栈 寄存器

二、从数组的内存说起


一个 数组的内存图

首先,我们有这样一组代码:

1 public class HelloWorld{ 
2  public static void main(String[] args){ 
3     int[] array = new int[2]; 
4     System.out.println(array); 
5     System.out.println(array[0]); 
6     System.out.println(array[1]);     
7     array[0]= 1; 
8     array[1]= 2; 
9     System.out.println(array); 
10     System.out.println(array[0]); 
11    System.out.println(array[1]); 
  } 
} 

看这张图:
记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

“.class”文件里面主要保存的就是main方法,
而图中过程就是 “进栈”的过程,并且为main方法开辟了一个新的空间。

继续来看

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

“int[] array” 左边其实是堆当中数组的地址值
所以“array”这个变量存储的其实是数组的地址值
然后根据地址进行寻找数组

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

输出的时候,会自动找到数组所有相关信息

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

当程序执行到赋值语句时
根据数组的地址值找到数组
并且找到索引位置进行修改数值
然后打印输出的时候,又会重复此前的步骤,进行寻址,取值

两个数组的内存图

1、新建数组的情况

如果在刚才的main方法中添加一个这样的语句

int[] array2 = new int[10]; 

此时,需要我们记住只要 new 了,它就会在堆当中 开辟出一个新的空间 ,也可以说是 新的内存空间

2、传递地址

如果添加的是这种语句呢?

int[] array2 = array; 

此时,堆当中还是只有那一个数组,只是将 array 的地址值传递给 array2 ,,因为它们的地址值相等,当给 array2 赋值时,更改的内容就是原来 array 里面的内容,也就是 : 两个引用指向同一个数组的情况

三、来看对象的内存

一个对象的内存图

首先,还是得有一段代码

public class student{ 
  String name; 
  String ssex; 
  int age; 
  public void study(){ 
    System.out.println("正在学习。。。。"); 
  } 
  public void eat(){ 
    System.out.println("正在吃饭。。。。"); 
  } 
} 

既然是对象,那就还得有一段代码,来使用这个student类

 public class TestStudent{ 
   public static void main(String[] args){ 
     Student stu = new Student(); 
     System.out.println(stu.name); 
     System.out.println(stu.ssex); 
     System.out.println(stu.age); 
      
     stu.name = "小杜"; 
     stu.age = 20; 
     stu.ssex = "男"; 
      
     System.out.println(stu.name); 
     System.out.println(stu.ssex); 
     System.out.println(stu.age); 
    stu.study(); 
    stu.eat(); 
   } 
 } 

那就从图看起来
记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

java中执行程序,首先是从main方法开始执行的
所以它必须第一个进栈

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

此处要 注意 !!!
当new Student()时
Student.class中的成员方法地址值会保存在堆当中
所以要记住,对于引用类型,都是地址在传递

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

所谓的stu.name
就是在调用成员变量,所以通过地址值来进行寻址
找到之后就进行更改
比如后面的语句
stu.name = "小杜" ;

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

对象.成员方法
通过地址值找到所要找的内容
然后开始进栈
当方法执行完毕后就会出现 “弹栈”
然后执行下一条语句
在我们这段代码中,下一条语句还是调用成员方法
所以study方法执行玩之后就会被弹出
进行下一条指令
调用eat方法

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图


两个对象使用同一个方法时的内存图

比如: 
  Student stu = new Student(); 
  Student stu2 = new Student(); 
  …… 

都是指向方法区的同一块方法的同一块地址空间


两个引用指向同一个对象的内存图

Student stu = new Student(); 
Student stu2 = stu; 
…… 

寻找stu的地址值,然后根据stu的地址值进行调用方法


使用对象类型作为方法的参数

比如代码中有这么两三行 
  public static void method(Student stu){ 
    System.out.println(stu.eat); 
    …… 
  } 

当一个对象作为方法的参数时,传递到方法中时,实际传递进去的是对象的地址值


使用对象类型作为方法的返回值

public static Student eat(){ 
  Student stu =new Student(); 
  stu.study(); 
  stu.name = "小杜"; 
  return stu; 
} 

当使用一个对象类型作为方法的返回值时
返回值其实就是对象的地址值


四、字符串常量池

字符串常量池:程序当中直接写上的双引号字符串,就在字符串常量池当中

所以:

对于基本类型来说,== 比较的是数值

对于引用类型来说 ,== 比较的是地址值

因为内容不可变性,所以可以共享的

而且字符串的效果相当于char[]数组,但是底层原理是byte[]数组,所以它会在存储的过程中自动转换成byte[]数组

借用一张网上的图

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

顺便提一下static关键字

根据类名称访问静态成员变量的时候,全程和对象是没有关系的,只和类有关系。


五、继承中的内存图

图片来源网络:

记Java中有关内存的简单认识
一、Java内存划分
二、从数组的内存说起
一个 数组的内存图
两个数组的内存图
三、来看对象的内存
一个对象的内存图
两个对象使用同一个方法时的内存图
两个引用指向同一个对象的内存图
使用对象类型作为方法的参数
使用对象类型作为方法的返回值
四、字符串常量池
五、继承中的内存图

也就是父类空间优先于子类对象的产生,在每次创建子类对象时,先初始化父类空间,再创建子类对象本身。