中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Java中的對象

發布時間:2021-10-14 10:42:26 來源:億速云 閱讀:150 作者:iii 欄目:編程語言

本篇內容介紹了“如何理解Java中的對象”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

堆(heap)和棧(stack)

堆是一塊內存,用來存放對象

棧是另一塊內存,用來執行方法并存儲局部變量,遵循后進先出的原則;

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="棧 堆" />

這里簡單介紹一下上面的流程

  1. main方法壓入棧中,創建局部變量live(對象的引用)

  2. 創建對象live,在堆中開辟內存,將live放入堆中

  3. live調用fun方法,將fun壓入棧中(此時fun在棧頂)

  4. fun執行完成,出棧,繼續執行main方法

  5. 最后main方法執行完成,也出棧,程序結束

這里可能有朋友要問了,那如果屬性是一個引用呢?它要存放在哪里?

引用存放在堆里,引用指向的對象也存放在堆里,只不過是堆的另一個地方

如下圖所示:堆中 live對象的屬性 liveRef 指向了另一個對象(live對象2)

如何理解Java中的對象

為啥要先介紹堆和棧呢?

因為堆和棧跟對象的生活息息相關

如果用人來比作對象的話,那堆就是人的家,棧就是外面的世界

我們出生在家里,跟外面的世界打交道,最后在家里。。。

對象的創建(生)

生存還是毀滅,這是一個問題。

-- 莎士比亞《哈姆萊特》

在Java的花花世界中,這也是個問題,不過是個有答案的問題;

答案就在下面。。。

如何理解Java中的對象

這里我們先把問題簡化

因為我們最常見的創建對象是通過new創建,而new對象的核心就是通過構造函數來實現,所以我們這里簡單起見,著重介紹構造函數,其他的后面等到虛擬機部分再介紹

構造函數的分類:

  • 無參構造函數

  • 有參構造函數

構造函數和普通方法的區別

  1. 構造函數沒有返回類型

  2. 構造函數名與類名一致

關于編譯器的默認操作

  1. 如果沒有定義構造函數,編譯器會默認創建一個無參構造函數

  2. 如果子類定義了有參構造函數,且沒有顯示調用父類的構造函數,則編譯器默認調用父類的無參構造函數

當你自己有創建構造函數(無參或有參)時,編譯器都不會再去創建構造函數

構造函數的重載:

很常用,一般用來設置屬性的默認值

具體做法就是多個構造函數層層調用(又來套娃了)

下面舉個例子:

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()即可調用父類對應的構造函數或方法(下面代碼有演示)

構造函數的執行順序

  1. 如果子類Dog繼承父類Animal,那么會先調用父類的構造函數,再調用子類的構造函數

  2. 如果父類Animal上面還有父類,會繼續往上調用

  3. 上面這個過程就叫做“構造函數鏈

這個關系有點像是:子女和父母的關系,子女要想出生,必須先讓爺爺奶奶把父母生出來,然后父母才能生子女

所以這里如果我們要構造子類,必須先構造父類;如果父類還有父類,則繼續延伸,一直到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時,該對象會被標記為沒用的對象,等待回收

上面都是假設引用是指向對象的最后一個引用的情況,如果有多個引用指向同一個對象,那么要等到引用都消失,對象才會被標記為可回收,即沒用的東西

總結

  1. 堆和棧

堆存放對象,棧用來執行方法并存放局部變量

  1. 對象的創建

主要通過構造函數來創建,比如new對象

如果是反序列化來創建對象,則不會構造,因為構造后,對象的屬性會被重新初始化,那么序列化的屬性值就被抹掉了(前面的Java中的IO流有涉及)

如果子類有父類,則先調用父類的構造函數,如果父類還有父類,則依次類推,直到Object超類

  1. 對象的回收

當指向對象的最后一個引用消失時,這個對象就會變成沒用的對象,等待著垃圾收集器的回收

“如何理解Java中的對象”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

瑞丽市| 井冈山市| 祁阳县| 霍山县| 双鸭山市| 淮安市| 和顺县| 洛川县| 和政县| 多伦县| 平江县| 龙州县| 开化县| 独山县| 额尔古纳市| 射洪县| 包头市| 霞浦县| 县级市| 汾阳市| 桐乡市| 进贤县| 东明县| 浦北县| 无棣县| 年辖:市辖区| 东海县| 陈巴尔虎旗| 肃宁县| 伊金霍洛旗| 新民市| 临汾市| 旬邑县| 仙桃市| 徐汇区| 平定县| 平利县| 南平市| 尼玛县| 秭归县| 六枝特区|