Java實例化對象過程中的內存分配:
https://blog.csdn.net/qq_36934826/article/details/82685791
問題引入這里先定義一個很不標准的“書”類,這里為了方便演示就不對類的屬性進行封裝了。
class Book{ String name; //書名 double price; //價格 public void getInfo(){ System.out.println("name:"+name+";price:"+price); }}1問題引入這里先定義一個很不標准的“書”類,這里為了方便演示就不對類的屬性進行封裝了。
class Book{ String name; //書名 double price; //價格 public void getInfo(){ System.out.println("name:"+name+";price:"+price); }}1234567在這個類中定義了兩個屬性和一個方法,當然也是可以定義多和類和多個方法的。 類現在雖然已經定義好了,但是一個類要使用它必須要實例化對象,那么對象的定義格式有一下兩種格式:
//聲明並實例化對象: 類名稱 對象名稱 = new 類名稱()Book book = new Book();123//分步完成聲明和實例操作: // |- 聲明對象: 類名稱 對象名稱 = null;Book book = null;// |- 實例化對象: 對象名稱 = new 類名稱();book = new Book();12345對象屬於引用數據類型,其和基本數據類型最大的不同在於引用數據類型需要進行內存分配,而關鍵字new主要的功能就是開辟內存空間,也就是說只要是使用引用數據類型就必須使用關鍵字new來開辟空間。有些時候我們需要對對象屬性進行操作,那么其中的堆棧內存空間又是如何分配的呢?接下來我們來分析一下其中的過程。
堆內存與棧內存如果想對對象操作的過程進行內存分析,首先要了解兩塊內存空間的概念:
堆內存:保存每一個對象的屬性內容,堆內存需要用關鍵字new才能開辟。棧內存:保存的是一塊堆內存的地址。堆內存很好理解,可能有人會有疑問為什么會有棧內存,舉個例子,好比學校有很多教室,每個教室有一個門牌號,教室內放了很多的桌椅等等,這個編號就好比地址,老師叫小明去一個教室拿東西,老師必須把房間號告訴小明才能拿到,也就是為什么地址必須存放在一個地方,而這個地方在計算機中就是棧內存。
對象空屬性我們先實例化一個對象,並對其的屬性不設置任何值
public class Test{ public static void main(String args[]){ Book book = new Book(); book.getInfo(); }}123456運行結果如下:
name:null;price:0.01其內存變化圖如下:
使用關鍵字new就在棧內存中開辟一個空間存放book對象,並且指向堆內存的一個空間,此時並未對其賦值,所以始終指向默認的堆內存空間。
操作對象屬性我們先聲明並實例化Book類,並對實例出的book對象操作其屬性內容。
public class Test{ public static void main(String args[]){ Book book = new Book(); book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}12345678編譯執行后的結果如下:
name:深入理解JVM;price:99.81內存變化圖如下:
分步實例化對象示例代碼如下:
public class Test{ public static void main(String args[]){ Book book = null; //聲明對象 book = new Book(); //實例化對象 book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}123456789很明顯結果肯定和前面一樣
name:深入理解JVM;price:99.81表面沒什么區別,但是內存分配過程卻不一樣,接下來我們來分析一下
任何情況下只要使用了new就一定要開辟新的堆內存空間,一旦堆內存空間開辟了,里面就一定會所有類中定義的屬性內容,此時所有的屬性內容都是其對應數據類型的默認值。
直觀的說就是棧內存先要指向一個null,然后等待開辟新的棧內存空間后才能指向其屬性內容。
NullPointerException的出現那么如果使用了沒有實例化的對象,就會出現最常見也是最讓人頭疼的一個異常NullPointerException,像下面的代碼
public class Test{ public static void main(String args[]){ Book book = null;// book = new Book(); //實例化的這一步被注釋 book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}123456789在編譯的過程是不會出錯的,因為只有語法錯誤才會在編譯時中斷,而這種邏輯性錯誤能成功編譯,但是執行的時候卻會拋出NullPointerException異常。 運行結果:
Exception in thread "main" java.lang.NullPointerException at language.Test.main(Test.java:19)1空指針異常是平時遇到最多的一類異常,只要是引用數據類型都有可能出現它。這種異常的出現也是很容易理解的,猶如你說今天被一只恐龍追着跑,恐龍早就在幾個世紀前就滅絕了,現實生活中不可能存在,當然人們就會認為你說的這句話是謊言。在程序中也一樣,沒有被實例化的對象直接調用其中的屬性或者方法,肯定會報錯。
引用數據分析引用是整個java中的核心精髓,引用類似於C++中的指針概念,但是又比指針的概念更加簡單。 舉個簡單的例子,比如李華的小名叫小華,一天李華因為生病向老師請假了,老師問今天誰請假了,說李華請假了和小華請假了都是一個意思,小華是李華的別名,他們兩個都是對應一個個體。 如果代碼里面聲明兩個對象,並且使用了關鍵字new為兩個對象分別進行了對象的實例化操作,那么一定是各自占用各自的堆內存空間,並且不會互相影響。
例如:聲明兩個對象
public class Test{ public static void main(String args[]){ Book bookA = new Book(); Book bookB = new Book();
bookA.name = "深入理解JVM"; bookA.price = 99.8; bookA.getInfo();
bookB.name = "Java多線程"; bookB.price = 69.8; bookB.getInfo(); }}1234567891011121314運行結果如下:
name:深入理解JVM;price:99.8name:Java多線程;price:69.812我們來分析一下內存的變化
接下來我們看看那對象引用傳遞
例如:對象引用傳遞
public class Test{ public static void main(String args[]){ Book bookA = new Book(); //聲明並實例化對象 Book bookB = null; //聲明對象 bookA.name = "深入理解JVM"; bookA.price = 99.8; bookB = bookA; //引用傳遞 bookB.price = 69.8; bookA.getInfo(); }}1234567891011運行結果如下:
name:深入理解JVM;price:69.81嚴格來講bookA和bookB里面保存的是對象的地址信息,所以以上的引用過程就屬於將bookA的地址賦給了bookB,此時兩個對象指向的是同一塊堆內存空間,因此任何一個對象修改了堆內存之后都會影響其他對象。
一塊堆內存可以同時被多個棧內存所指向,但是反過來,一塊棧內存只能保存一塊堆內存空間的地址。
垃圾的產生先看如下代碼:
public class Test{ public static void main(String args[]){ Book bookA = new Book(); //聲明並實例化對象 Book bookB = new Book(); //聲明並實例化對象 bookA.name = "深入理解JVM"; bookA.price = 99.8; bookB.name = "Java多線程"; bookB.price = 69.8; bookB = bookA; //引用關系 bookB.price = 120.8; bookA.getInfo(); }}12345678910111213運行結果如下:
name:深入理解JVM;price:120.81整個過程內存又發生了什么變化呢?我們來看一下
在此過程中原來bookB所指向的堆內存無棧內存指向,一塊沒有任何棧內存指向的堆內存空間就將成為垃圾,等待被java中的回收機制回收,回收之后會釋放掉其占用的空間。
雖然在java中支持了自動的垃圾收集處理,但是在代碼的編寫過程中應該盡量減少垃圾空間的產生。
歡迎來我的博客網站逛一逛~blog.beifengtz.com--------------------- 作者:beifengtz 來源:CSDN 原文:https://blog.csdn.net/qq_36934826/article/details/82685791 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!234567在這個類中定義了兩個屬性和一個方法,當然也是可以定義多和類和多個方法的。 類現在雖然已經定義好了,但是一個類要使用它必須要實例化對象,那么對象的定義格式有一下兩種格式:
//聲明並實例化對象: 類名稱 對象名稱 = new 類名稱()Book book = new Book();123//分步完成聲明和實例操作: // |- 聲明對象: 類名稱 對象名稱 = null;Book book = null;// |- 實例化對象: 對象名稱 = new 類名稱();book = new Book();12345對象屬於引用數據類型,其和基本數據類型最大的不同在於引用數據類型需要進行內存分配,而關鍵字new主要的功能就是開辟內存空間,也就是說只要是使用引用數據類型就必須使用關鍵字new來開辟空間。有些時候我們需要對對象屬性進行操作,那么其中的堆棧內存空間又是如何分配的呢?接下來我們來分析一下其中的過程。
堆內存與棧內存如果想對對象操作的過程進行內存分析,首先要了解兩塊內存空間的概念:
堆內存:保存每一個對象的屬性內容,堆內存需要用關鍵字new才能開辟。棧內存:保存的是一塊堆內存的地址。堆內存很好理解,可能有人會有疑問為什么會有棧內存,舉個例子,好比學校有很多教室,每個教室有一個門牌號,教室內放了很多的桌椅等等,這個編號就好比地址,老師叫小明去一個教室拿東西,老師必須把房間號告訴小明才能拿到,也就是為什么地址必須存放在一個地方,而這個地方在計算機中就是棧內存。
對象空屬性我們先實例化一個對象,並對其的屬性不設置任何值
public class Test{ public static void main(String args[]){ Book book = new Book(); book.getInfo(); }}123456運行結果如下:
name:null;price:0.01其內存變化圖如下:
使用關鍵字new就在棧內存中開辟一個空間存放book對象,並且指向堆內存的一個空間,此時並未對其賦值,所以始終指向默認的堆內存空間。
操作對象屬性我們先聲明並實例化Book類,並對實例出的book對象操作其屬性內容。
public class Test{ public static void main(String args[]){ Book book = new Book(); book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}12345678編譯執行后的結果如下:
name:深入理解JVM;price:99.81內存變化圖如下:
分步實例化對象示例代碼如下:
public class Test{ public static void main(String args[]){ Book book = null; //聲明對象 book = new Book(); //實例化對象 book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}123456789很明顯結果肯定和前面一樣
name:深入理解JVM;price:99.81表面沒什么區別,但是內存分配過程卻不一樣,接下來我們來分析一下
任何情況下只要使用了new就一定要開辟新的堆內存空間,一旦堆內存空間開辟了,里面就一定會所有類中定義的屬性內容,此時所有的屬性內容都是其對應數據類型的默認值。
直觀的說就是棧內存先要指向一個null,然后等待開辟新的棧內存空間后才能指向其屬性內容。
NullPointerException的出現那么如果使用了沒有實例化的對象,就會出現最常見也是最讓人頭疼的一個異常NullPointerException,像下面的代碼
public class Test{ public static void main(String args[]){ Book book = null;// book = new Book(); //實例化的這一步被注釋 book.name = "深入理解JVM"; book.price = 99.8; book.getInfo(); }}123456789在編譯的過程是不會出錯的,因為只有語法錯誤才會在編譯時中斷,而這種邏輯性錯誤能成功編譯,但是執行的時候卻會拋出NullPointerException異常。 運行結果:
Exception in thread "main" java.lang.NullPointerException at language.Test.main(Test.java:19)1空指針異常是平時遇到最多的一類異常,只要是引用數據類型都有可能出現它。這種異常的出現也是很容易理解的,猶如你說今天被一只恐龍追着跑,恐龍早就在幾個世紀前就滅絕了,現實生活中不可能存在,當然人們就會認為你說的這句話是謊言。在程序中也一樣,沒有被實例化的對象直接調用其中的屬性或者方法,肯定會報錯。
引用數據分析引用是整個java中的核心精髓,引用類似於C++中的指針概念,但是又比指針的概念更加簡單。 舉個簡單的例子,比如李華的小名叫小華,一天李華因為生病向老師請假了,老師問今天誰請假了,說李華請假了和小華請假了都是一個意思,小華是李華的別名,他們兩個都是對應一個個體。 如果代碼里面聲明兩個對象,並且使用了關鍵字new為兩個對象分別進行了對象的實例化操作,那么一定是各自占用各自的堆內存空間,並且不會互相影響。
例如:聲明兩個對象
public class Test{ public static void main(String args[]){ Book bookA = new Book(); Book bookB = new Book();
bookA.name = "深入理解JVM"; bookA.price = 99.8; bookA.getInfo();
bookB.name = "Java多線程"; bookB.price = 69.8; bookB.getInfo(); }}1234567891011121314運行結果如下:
name:深入理解JVM;price:99.8name:Java多線程;price:69.812我們來分析一下內存的變化
接下來我們看看那對象引用傳遞
例如:對象引用傳遞
public class Test{ public static void main(String args[]){ Book bookA = new Book(); //聲明並實例化對象 Book bookB = null; //聲明對象 bookA.name = "深入理解JVM"; bookA.price = 99.8; bookB = bookA; //引用傳遞 bookB.price = 69.8; bookA.getInfo(); }}1234567891011運行結果如下:
name:深入理解JVM;price:69.81嚴格來講bookA和bookB里面保存的是對象的地址信息,所以以上的引用過程就屬於將bookA的地址賦給了bookB,此時兩個對象指向的是同一塊堆內存空間,因此任何一個對象修改了堆內存之后都會影響其他對象。
一塊堆內存可以同時被多個棧內存所指向,但是反過來,一塊棧內存只能保存一塊堆內存空間的地址。
垃圾的產生先看如下代碼:
public class Test{ public static void main(String args[]){ Book bookA = new Book(); //聲明並實例化對象 Book bookB = new Book(); //聲明並實例化對象 bookA.name = "深入理解JVM"; bookA.price = 99.8; bookB.name = "Java多線程"; bookB.price = 69.8; bookB = bookA; //引用關系 bookB.price = 120.8; bookA.getInfo(); }}12345678910111213運行結果如下:
name:深入理解JVM;price:120.81整個過程內存又發生了什么變化呢?我們來看一下
在此過程中原來bookB所指向的堆內存無棧內存指向,一塊沒有任何棧內存指向的堆內存空間就將成為垃圾,等待被java中的回收機制回收,回收之后會釋放掉其占用的空間。
雖然在java中支持了自動的垃圾收集處理,但是在代碼的編寫過程中應該盡量減少垃圾空間的產生。--------------------- 作者:beifengtz 來源:CSDN 原文:https://blog.csdn.net/qq_36934826/article/details/82685791 版權聲明:本文為博主原創文章,轉載請附上博文鏈接!