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

概述

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

內部類介紹和分類

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

常規內部類

@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 內部類內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: