您好,登錄后才能下訂單哦!
本篇內容介紹了“如何理解Java中的對象”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
堆是一塊內存,用來存放對象
棧是另一塊內存,用來執行方法并存儲局部變量,遵循后進先出的原則;
PS:棧并不存儲方法,只是執行方法,執行完方法后,會將方法彈出棧(方法存在方法區)
下面我們用實際代碼,來看下堆和棧的區別
代碼如下:
public class LiveAndDeathDemo { // 基本類型屬性 private int a; public static void main(String[] args) { LiveAndDeathDemo live = new LiveAndDeathDemo(1); live.fun(); } public void fun(){ int temp = 10; System.out.println(temp); } public LiveAndDeathDemo(int a) { this.a = a; } public int getA() { return a; } public void setA(int a) { this.a = a; } }
可以看到,有一個實例變量a(堆), 兩個方法main和fun,其中fun有一個局部變量temp(棧)
它們的區別如下所示:
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gpfqb6nb8mj30lq0d2wf4.jpg" alt="棧 堆" />
這里簡單介紹一下上面的流程
main方法壓入棧中,創建局部變量live(對象的引用)
創建對象live,在堆中開辟內存,將live放入堆中
live調用fun方法,將fun壓入棧中(此時fun在棧頂)
fun執行完成,出棧,繼續執行main方法
最后main方法執行完成,也出棧,程序結束
這里可能有朋友要問了,那如果屬性是一個引用呢?它要存放在哪里?
堆
引用存放在堆里,引用指向的對象也存放在堆里,只不過是堆的另一個地方
如下圖所示:堆中 live對象的屬性 liveRef
指向了另一個對象(live對象2)
為啥要先介紹堆和棧呢?
因為堆和棧跟對象的生活息息相關
如果用人來比作對象的話,那堆就是人的家,棧就是外面的世界
我們出生在家里,跟外面的世界打交道,最后在家里。。。
生存還是毀滅,這是一個問題。
-- 莎士比亞《哈姆萊特》
在Java的花花世界中,這也是個問題,不過是個有答案的問題;
答案就在下面。。。
這里我們先把問題簡化
因為我們最常見的創建對象是通過new創建,而new對象的核心就是通過構造函數來實現,所以我們這里簡單起見,著重介紹構造函數,其他的后面等到虛擬機部分再介紹
構造函數的分類:
無參構造函數
有參構造函數
構造函數和普通方法的區別:
構造函數沒有返回類型
構造函數名與類名一致
關于編譯器的默認操作:
如果沒有定義構造函數,編譯器會默認創建一個無參構造函數
如果子類定義了有參構造函數,且沒有顯示調用父類的構造函數,則編譯器默認調用父類的無參構造函數
當你自己有創建構造函數(無參或有參)時,編譯器都不會再去創建構造函數
構造函數的重載:
很常用,一般用來設置屬性的默認值
具體做法就是多個構造函數層層調用(又來套娃了)
下面舉個例子:
public class LiveAndDeathDemo { private int a; private String name; public LiveAndDeathDemo(){ this(1); } public LiveAndDeathDemo(int a) { this(a, "JavaLover"); } public LiveAndDeathDemo(int a, String name) { this.a = a; this.name = name; } // 省略getter,setter }
用圖表示的話,就是下面這個樣子
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gpfrldwz7wj30mm0fkt99.jpg" alt="構造函數 調用層級" />
構造函數的私有化
如果構造函數私有化,那么它要怎么用呢?
私有化說明只有類本身可以調用,這種主要用在工廠方法中
比如Java中的LocalDate,源碼如下:
public final class LocalDate implements Temporal, TemporalAdjuster, ChronoLocalDate, Serializable { // 構造函數私有化 private LocalDate(int year, int month, int dayOfMonth) { this.year = year; this.month = (short) month; this.day = (short) dayOfMonth; } // 對外提供一個靜態方法,用來創建對象實例 public static LocalDate of(int year, int month, int dayOfMonth) { YEAR.checkValidValue(year); MONTH_OF_YEAR.checkValidValue(month); DAY_OF_MONTH.checkValidValue(dayOfMonth); return create(year, month, dayOfMonth); } }
這種用法在LocalDate這種工具類中用的比較多,還有就是單例模式(后面設計模式時再介紹)
上面介紹的構造函數沒有介紹到父類,下面開始介紹
如果有父類,構造函數的有哪些不一樣的地方
this和super:
在介紹父類的構造函數之前,有必要介紹下這個super
this
指向當前類
super
指向父類
super
用來顯式調用父類相關屬性和方法(包括構造函數)
比如super.filedA
, super.fun()
等
這里有個特例,如果是在子類的構造函數中或者覆寫方法中,則直接調用super()即可調用父類對應的構造函數或方法(下面代碼有演示)
構造函數的執行順序
如果子類Dog
繼承父類Animal
,那么會先調用父類的構造函數,再調用子類的構造函數;
如果父類Animal上面還有父類,會繼續往上調用;
上面這個過程就叫做“構造函數鏈”
這個關系有點像是:子女和父母的關系,子女要想出生,必須先讓爺爺奶奶把父母生出來,然后父母才能生子女
所以這里如果我們要構造子類,必須先構造父類;如果父類還有父類,則繼續延伸,一直到Object超類為止
下面用代碼演示下這個層層調用的過程:
public class SuperDemo extends Father{ public SuperDemo() { // 1.1 這里顯示調用父類的構造函數 // 1.2 Super必須放在構造函數的第一行 super(); System.out.println("sub construct"); } public static void main(String[] args) { SuperDemo demo = new SuperDemo(); } } class Father{ public Father() { // 2. 這里沒有顯示調用父類(Object)的構造函數,編譯器會自己去調用 System.out.println("father construct"); } } /** 假設下面這個Object就是我們的超類 class Object{ public Object(){ // 3. 最終的構造函數,會調到這里為止 } } **/
輸出如下:
father construct sub construct
可以看到,先調用父類Father的構造函數,再調用子類的構造函數
他們之間的繼承關系如下:
<img src="https://tva1.sinaimg.cn/large/008eGmZEly1gpfz2zqrknj30pa0hmabg.jpg" alt="SuperDemo的繼承關系" />
圖示說明:
左邊的虛線表示層層往上調用,直到超類Object
右邊的實現表示上面的構造完成會回到下面那一層,繼續構造,直到當前類
好了,構造的過程大致就是這個樣子了,還有很多其他方面的細節(比如類的初始化等)這里先不介紹了,太多了,放到后面介紹
對象的回收是在程序內存不夠用時,將沒用的對象(可回收)進行釋放的一種操作,這個操作是由垃圾收集器GC來完成的
什么是沒用的對象?
沒用的對象就是可回收的對象
說人話:當指向對象A的最后一個引用ref消失時,這個對象A就會變成沒用的對象,等待著垃圾收集器的回收
那怎么才算引用消失呢?
基本分為兩種情況:
如果引用是局部變量,那當引用所在的方法執行完畢時,引用就會被釋放,那么該對象隨即也就會被標記為沒用的對象,等待回收
當引用指向其他對象或者null時,該對象會被標記為沒用的對象,等待回收
上面都是假設引用是指向對象的最后一個引用的情況,如果有多個引用指向同一個對象,那么要等到引用都消失,對象才會被標記為可回收,即沒用的東西
堆和棧
堆存放對象,棧用來執行方法并存放局部變量
對象的創建
主要通過構造函數來創建,比如new對象
如果是反序列化來創建對象,則不會構造,因為構造后,對象的屬性會被重新初始化,那么序列化的屬性值就被抹掉了(前面的Java中的IO流有涉及)
如果子類有父類,則先調用父類的構造函數,如果父類還有父類,則依次類推,直到Object超類
對象的回收
當指向對象的最后一個引用消失時,這個對象就會變成沒用的對象,等待著垃圾收集器的回收
“如何理解Java中的對象”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。