記Java中有關記憶體的簡單認識
一、Java記憶體劃分
分為五個部分,可以參考這篇筆記簡單認識一下:
//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]);
}
}
看這張圖:
「.class」文件裡面主要保存的就是main方法, 而圖中過程就是 「進棧」的過程,並且為main方法開闢了一個新的空間。 繼續來看 |
---|
「int[] array」 左邊其實是堆當中數組的地址值 所以「array」這個變數存儲的其實是數組的地址值 然後根據地址進行尋找數組 |
---|
輸出的時候,會自動找到數組所有相關資訊 |
---|
當程式執行到賦值語句時 根據數組的地址值找到數組 並且找到索引位置進行修改數值 然後列印輸出的時候,又會重複此前的步驟,進行定址,取值 |
---|
兩個數組的記憶體圖
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中執行程式,首先是從main方法開始執行的 所以它必須第一個進棧 |
---|
此處要 注意 !!! 當new Student()時 Student.class中的成員方法地址值會保存在堆當中 所以要記住,對於引用類型,都是地址在傳遞 |
---|
所謂的stu.name 就是在調用成員變數,所以通過地址值來進行定址 找到之後就進行更改 比如後面的語句 stu.name = “小杜” ; |
---|
對象.成員方法 通過地址值找到所要找的內容 然後開始進棧 當方法執行完畢後就會出現 「彈棧」 然後執行下一條語句 在我們這段程式碼中,下一條語句還是調用成員方法 所以study方法執行玩之後就會被彈出 進行下一條指令 調用eat方法 |
---|
兩個對象使用同一個方法時的記憶體圖
比如:
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[]數組
借用一張網上的圖
順便提一下static關鍵字
根據類名稱訪問靜態成員變數的時候,全程和對象是沒有關係的,只和類有關係。
五、繼承中的記憶體圖
圖片來源網路:
也就是父類空間優先於子類對象的產生,在每次創建子類對象時,先初始化父類空間,再創建子類對象本身。