Java內(nèi)部類深入理解

眾所周知,外部頂級類的類名需和類文件名相同,只能使用public和default。而內(nèi)部類是指在外部類的內(nèi)部再定義一個類,類名不需要和文件名相同。內(nèi)部類可以是靜態(tài)static的,也可用public,default(包限定),protected和private修飾。

內(nèi)部類:

概念:

我們所說的內(nèi)部類,官方的叫法是嵌套類(Nested Classes)。嵌套類包括靜態(tài)內(nèi)部類(Static Nested Classes)和內(nèi)部類(Inner Classes)。而非靜態(tài)內(nèi)部類分為成員內(nèi)部類,局部內(nèi)部類(Local Classes)和匿名內(nèi)部類(Anonymous Classes)。

image.png

內(nèi)部類是一個編譯是的概念,一旦編譯成功,就會成為完全不同的兩個類,分別為outer.class和outer$inner.class類。所以內(nèi)部類的成員變量/方法名可以和外部類的相同。

內(nèi)部類有什么作用?

1.內(nèi)部類可以很好的實現(xiàn)隱藏
一般的非內(nèi)部類,是不允許有 private 與protected權(quán)限的,但內(nèi)部類可以
2.內(nèi)部類擁有外圍類的所有元素的訪問權(quán)限 (private修飾也能訪問)
3.可是實現(xiàn)多重繼承 (讓多個內(nèi)部類分別繼承多個其他類,使外部類可以同時獲取多個其他類的屬性)
4.可以避免修改接口而實現(xiàn)同一個類中兩種同名方法的調(diào)用。(外部類繼承,讓內(nèi)部類實現(xiàn)接口)

靜態(tài)內(nèi)部類:

形如:

public class OuterClass {
    private String name;

    static class StaticInerCls{
        private String name;
    }
}

靜態(tài)內(nèi)部類除了訪問權(quán)限修飾符比外圍類多以外, 和外圍類沒有區(qū)別, 只是代碼上將靜態(tài)內(nèi)部類組織在了外部類里面。
創(chuàng)建靜態(tài)內(nèi)部類:以Class.Iner的形式

OuterClass.StaticInerCls staticInerCls = new OuterClass.StaticInerCls();  
靜態(tài)內(nèi)部類與普通內(nèi)部類的區(qū)別
  1. 靜態(tài)內(nèi)部類不持有外部類的引用 在普通內(nèi)部類中,我們可以直接訪問外部類的屬性、方法,即使是private類型也可以訪問,這是因為內(nèi)部類持有一個外部類的引用,可以自由訪問。而靜態(tài)內(nèi)部類,則只可以訪問外部類的靜態(tài)方法和靜態(tài)屬性(即使是private權(quán)限也能訪問,這是由其代碼位置所決定的),其他則不能訪問。
  2. 靜態(tài)內(nèi)部類不依賴外部類 普通內(nèi)部類與外部類之間是相互依賴的關(guān)系,內(nèi)部類實例不能脫離外部類實例,也就是說它們會同生同死,一起聲明,一起被垃圾回收器回收。而靜態(tài)內(nèi)部類是可以獨立存在的,即使外部類消亡了,靜態(tài)內(nèi)部類還是可以存在的。

非靜態(tài)內(nèi)部類:

非靜態(tài)內(nèi)部類能訪問外部類的一切成員, 包括私有成員。外部類雖然不能直接訪問內(nèi)部類的成員, 但是可以通過內(nèi)部類的實例訪問內(nèi)部類的私有成員。

成員內(nèi)部類:

形如:

public class OuterCls {
    private String name;
    public String getName(){
        return name;
    }

    class InerCls{
        private String name;

        public String getName(){
            return name;
        }
    }

}

成員內(nèi)部類可以直接使用外部類的所有成員和方法,即使是private修飾的。而外部類要訪問內(nèi)部類的所有成員變量和方法,內(nèi)需要通過內(nèi)部類的對象來獲取。(誰叫它是親兒子呢?) 要注意的是,成員內(nèi)部類不能含有static的變量和方法。因為成員內(nèi)部類需要先創(chuàng)建了外部類,才能創(chuàng)建它自己的。
創(chuàng)建內(nèi)部類對象方法,以object.new Iner的形式:

OuterCls outerCls = new OuterCls();
OuterCls.InerCls inerCls = outerCls.new InerCls();  

成員內(nèi)部類不能有static修飾的成員,但是卻允許定義常量。

public class OuterClass {
    private String name;

    static class StaticInerCls{
        private String name;
    }

    class InerCls{
        private String name;
        private static int id;    //不允許,會報錯
        private static final int TYPE = 0;   //允許
    }
}
靜態(tài)類的主要特性:

1:僅包含靜態(tài)成員。
2:無法實例化。
3:是密封的。
4:不能包含實例構(gòu)造函數(shù)。

為什么普通內(nèi)部類不能有靜態(tài)變量

1.成員內(nèi)部類 之所以叫做成員 就是說他是類實例的一部分 而不是類的一部分。
2.結(jié)構(gòu)上來說 他和你聲明的成員變量是一樣的地位 一個特殊的成員變量 而靜態(tài)的變量是類的一部分和實例無關(guān)。
3.非靜態(tài)內(nèi)部類能訪問外部類的一切屬性;靜態(tài)內(nèi)部類只能訪問外部類的靜態(tài)屬性。

內(nèi)部類中要想訪問外部類的非靜態(tài)成員,需要使用外部類進行引導(dǎo):外部內(nèi)名.this.屬性的名稱;想要訪問外部類靜態(tài)成員時,可以省略this:外部類名.屬性的名稱。

       /**
         * 獲取外部類靜態(tài)屬性
         * @return
         */
        public String getParentName() {
            return OuterClass.staticName;
        }

       /**
         * 獲取外部類非靜態(tài)屬性
         * @return
         */
        public String getParentName() {
            return OuterClass.this.name;
        }
局部內(nèi)部類:

指內(nèi)部類定義在方法體內(nèi),只能在該方法或條件的作用域內(nèi)才能使用,退出這寫作用域就無法引用。

作為非靜態(tài)內(nèi)部類的一種特殊形式, 非靜態(tài)內(nèi)部類的所有限制對局部類同樣成立。局部類不僅可以訪問外部類的所有成員,還可以訪問方法體的局部變量,但必須是final修飾的局部變量。

為什么局部類訪問局部變量,變量必須加上final?

場景:


    Object method(){
        int localVariable = 0;
        class Inner{
            void println(){
                System.out.println("localVariable " + localVariable++);
            }
        }
        Object in = new Inner();
        return in;
    }
}

這里的localVariable會變紅,提示需要給localVariable變量加final修飾。
解析:這是作用域的問題。在方法method執(zhí)行完成后,局部變量value就失效了,而在new Inner()產(chǎn)生的in對象還存在obj的引用,這樣對象就訪問了一個不存在的變量,是不允許的。iner還存在,在外面和后續(xù)調(diào)用該局部變量時,這個局部變量可能已經(jīng)失效了。但為什么加上final就可以保證能訪問呢?這里Java采用了一種copy local variable的方法實現(xiàn),定義為final的變量,會拷貝一份存到局部內(nèi)部類中,后續(xù)使用持續(xù)維護這個對象在生命周期內(nèi),所以可以繼續(xù)訪問。

修改之后:

    Object method(){
        final int[] localVariable = {0};
        class Inner {
            void println(){
                System.out.println("localVariable " + localVariable[0]++);
            }
        }
        Object in = new Inner();
        return in;
    }

還有一種解釋是局部變量可能在方法中值被修改,而導(dǎo)致內(nèi)部類得到的值不一致,于是用final來讓該引用不可改變。

注:final可以修飾的范圍有類,方法,屬性。修飾類,該類不可以被繼承;修飾方法,該方法不可以被子類重寫;修飾變量,該變量值不能被修改。

匿名內(nèi)部類:

定義:
new抽象類或者是接口,能夠獲得一個抽象類或者是接口的一個實現(xiàn)類對象,這個實現(xiàn)類對象沒有名字,所以稱之為匿名內(nèi)部類。本質(zhì)是一個繼承了類或者實現(xiàn)了接口的子類匿名對象。

匿名內(nèi)部類的條件:
1.匿名內(nèi)部類不能有構(gòu)造方法。
2.匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
3.匿名內(nèi)部類不能是public,protected,private,static。
4.只能創(chuàng)建匿名內(nèi)部類的一個實例。
5.一個匿名內(nèi)部類一定是在new的后面,用其隱含實現(xiàn)一個接口或?qū)崿F(xiàn)一個類。
6.因匿名內(nèi)部類為局部內(nèi)部類,所以局部內(nèi)部類的所有限制都對其生效。

    /**
     * 匿名內(nèi)部類
     */
    private Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            
        }
    });

Runnable只是一個接口,卻可以直接new出一個實例,創(chuàng)建的對象是這個接口的一個實現(xiàn)類對象,沒有名字,只能使用一次。

參考:https://juejin.cn/post/6986449929426173965

Github代碼參考地址:

https://github.com/running-libo/JavaPrinciples

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java 內(nèi)部類 分四種:成員內(nèi)部類、局部內(nèi)部類、靜態(tài)內(nèi)部類和匿名內(nèi)部類。 1、成員內(nèi)部類: 即作為外部類的一個成...
    ikaroskun閱讀 1,355評論 0 13
  • Advanced Language Features 知識點:一. static修飾符 static修飾符可以用來...
    風(fēng)景涼閱讀 505評論 0 0
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,679評論 18 399
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,812評論 0 11
  • 問:Java 常見的內(nèi)部類有哪幾種,簡單說說其特征? 答:靜態(tài)內(nèi)部類、成員內(nèi)部類、方法內(nèi)部類(局部內(nèi)部類)、匿名內(nèi)...
    Little丶Jerry閱讀 2,231評論 0 1

友情鏈接更多精彩內(nèi)容