首頁 > 軟體

一文帶你真正理解Java中的內部類

2022-08-31 10:00:04

概述

不知道大家在平時的開發過程中或者原始碼裡是否留意過內部類,那有思考過為什麼要有內部類,內部類都有哪幾種形式,靜態內部類和普通內部類有什麼區別呢?本篇文章主要帶領大家理解下這塊內容。

內部類介紹和分類

顧名思義,內部類是指一個類在另外一個類的內部,是定義在另一個類中的類。根據類的位置和屬性不同,可以分為下面幾種。

常規內部類

@Data
public class Tree {

    private String treeName;

    private String treeType;

    private List<Leaf> leafs;


    @Data
    public class Leaf {
        private String color;

        private String leafSize;

        public void show() {
            System.out.println("tree name: " + Tree.this.treeName);
            System.out.println("tree name: " + treeName);
        }
    }

    public static void main(String[] args) {
        Tree tree = new Tree();
        Leaf leaf = tree.new Leaf();
    }
}

上面就是一個內部類的例子,Leaf是Tree的內部類。

  • 內部類中可以直接存取外部類的資料,包括私有資料。
  • 常規內部類中的方法或者欄位不能是靜態的。
  • 內部類中可以使用如下的語法Tree.this.treeName
  • 內部類建立物件需要外部物件的存在,如下:
Tree tree = new Tree();
Leaf leaf = tree.new Leaf();

位元組碼分析:

我們檢視下內部類的位元組碼,如下圖:

我們看到內部類Leaf的構造方法init,實際上會隱式地將外部物件傳入,初始化,這樣才能在內部類中存取。

區域性內部類

區域性內部類,比如只有在一個方法內部建立。

@Data
public class Tree {

    private String treeName;

    private String treeType;

    private List<Leaf> leafs;

    public void treeRoot(int height) {
        class TreeRoot {
            private int rootHeight;

            public void showRootHeight() {
                this.rootHeight = height;
                System.out.println("root height " + height);
            }
        }
        TreeRoot root = new TreeRoot();
        root.showRootHeight();
    }
}
  • 區域性類不能用public或private存取說明符進行宣告,因為作用域只在這個區域性,沒有必要。
  • 區域性內部類可以完全將自己隱藏起來,體現良好的封裝性。
  • 區域性內部類可以直接存取方法的變數。

匿名內部類

匿名內部類,就更加簡潔了,連類名都省略了, 這個配合lambda食用,非常簡便,想必大家也經常使用了。

public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("runnable");
            }
        };

        Runnable runnable2 = () -> System.out.println("runnable");
    }

匿名內部類也體現了良好的封裝性和簡潔性。

靜態內部類

最後,再介紹下靜態內部類,這個也使用的非常頻繁。java原始碼中也有很多這樣的例子,比如HashMap中,Node節點就是一個靜態內部類。

如果用static來修飾一個內部類,那麼就是靜態內部類。這個內部類屬於外部類本身,但是不屬於外部類的任何物件。因此使用static修飾的內部類稱為靜態內部類。靜態內部類有如下規則:

  • 靜態內部類不能存取外部類的範例成員,只能存取外部類的類成員。
  • 外部類可以使用靜態內部類的類名作為呼叫者來存取靜態內部類的類成員,也可以使用靜態內部類物件存取其範例成員。

靜態內部類和普通內部類的區別

我們可以通俗按下面的方式理解:

內部類:就是我是你的一部分,我瞭解你,我知道你的全部,沒有你就沒有我。(所以內部類物件是以外部類物件存在為前提的)

靜態內部類:就是我跟你沒關係,自己可以完全獨立存在,但是我就借你的殼用一下,來隱藏自己。

從位元組碼角度上看,靜態內部類和非靜態內部類最大的區別是:非靜態內部類編譯後隱式儲存著外部類的參照(就算外部類物件沒用了也GC不掉),但是靜態內部類沒有。

內部類的作用

通過上面的瞭解,我想內部類還是有一定的意義的。

  • 內部類方法可以存取該類定義所在的作用域中的資料,包括私有的資料。
  • 內部類可以對同一個包中的其他類隱藏起來。

其實內部類更多的時候,不想把這個類暴露出去,它可能只是外部類的一個邏輯組成部分,不需要其他地方知道什麼,這時候我們用內部類更加的清楚。

到此這篇關於一文帶你真正理解Java中的內部類的文章就介紹到這了,更多相關Java 內部類內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com