1. 程式人生 > >Java——內部類的定義以及使用

Java——內部類的定義以及使用

內部類:在類內部進行其他類結構巢狀操作。

舉慄說明:

class Outter{
    private String msg = "Outter中的字串";
    //內部類
    class Inner{
        private String inMsg = "Inner中的字串";
        public void fun(){
            //直接呼叫外部類的私有屬性
            System.out.println(msg);
        }
    }
    public void test(){
        //生產內部類物件
        Inner in = new Inner();
        in.fun();
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.test();
    }
}

缺點:結構複雜
將Inner類提出來,主方法不變,實現相同的功能:

class Outter{
    private String msg = "Outter中的字串";  //因為這裡是private屬性,所以不能直接訪問,需提供getter方法
    public String getMsg(){
        return this.msg;
    }
    public void test(){
        //this表示當前物件
        Inner in = new Inner(this);
        in.fun();
    }
}
   
class Inner{
    private String inMsg = "Inner中的字串";
    private Outter out;  //通過構造方法給Inner內傳入一個Outter類,專業叫做【構造注入】
    //此時Outter是Inner內的普通屬性
    public Inner(Outter out){  //這裡的Outter out就是一個引數
        this.out = out;  //為Inner中的out變數初始化
    }
     public void fun(){
         System.out.println(out.getMsg());
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.test();
    }
}

提出來之後我們發現程式碼變得更加麻煩,難理解,此時我們在這裡可以提一下內部類的優點:

  • 內部類的優點
a.內部類與外部類可以方便的訪問彼此的私有域(包含私有方法,私有屬性)
存在私有內部類(靜態,成員均可)
【ArrayList中Node內部類,HashMap中Entry內部類(私有內部類)】
b.內部類是另外一種封裝(保護性),對外部的其他類隱藏(心臟包在人身體內部)
c.內部類可以實現Java單繼承的侷限。

- 使用內部類實現Java的多繼承:

class A{
    private String msg = "test";
    public String getMsg(){
        return msg;
    }
}
class B{
    private int age = 20;
    public int getAge(){
        return age;
    }
}
class C{
    class InnerClassA extends A{
        public String name(){
            return super.getMsg();
        }
    }
    class InnerClassB extends B{
        public int age(){
            return super.getAge();
        }
    }
    public String name(){
        return new InnerClassA().name();
    }
    public int age(){
        return new InnerClassB().age();
    }
}
public class Test{
    public static void main(String[] args){
        C c = new C();
        System.out.println(c.name());
        System.out.println(c.age());
    }
}

多繼承還是推薦多層繼承。

- 內部類和外部類的關係:(不推薦使用)

1.對於非靜態內部類,內部類的建立需要依賴外部類物件,在沒有外部類例項之前無法建立非靜態內部類。

2.內部類是一個相對獨立的個體,與外部類沒有is-a關係。

3.內部類可以直接訪問外部類的元素(包含私有域),但是外部類不可以直接訪問內部類元素,需要通過內部類的引用間接訪問。

針對於第三點:

class Outter{
    private String msg;
    private int age;
    //-----------------內部類-----------------
    class Inner{
        public void display(){
            msg = "test";  //直接使用
            //Outter.this.msg = "test";
            age = 20;  //直接使用
            //Outter.this.age = 20;
            System.out.println(msg);
            System.out.println(age);
        }
    }
    //---------------- -------------------------
    public void test(){
        Inner in = new Inner();
        in.display();
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.test();
    }
}

內外部類可以直接訪問彼此的私有屬性:

class Outter{
    //-------------------------------------
    class Inner{ //1...
        private String msg = "InnerClass";
    }
    //-----------------------------------------
    public void test(){
        Inner in = new Inner();//2...
        System.out.println(in.msg);
    }
}
public class Test{
    public static void main(String[] args){
        Outter out = new Outter();
        out.test();
    }
}
程式執行結果:
//InnerClass

1.說明了內外部類可以直接訪問彼此的私有屬性,首先必須建立外部類,才能建立內部類,建立內部類的時候就把外部類的物件傳進來了 ,所以可以直接用。
2.外部類訪問內部類需要建立內部類的物件以後才能用,這叫間接使用。

- 建立內部類語法(在外部類外部)

a.建立非靜態內部類

外部類.內部類  內部類引用 = new   外部類().new    內部類();

Outter.Inner  in = new   Outter().new    Inner();

b.建立靜態內部類

外部類.內部類    內部類引用 = new    外部類.內部類();

Outter.Inner     in   =   new  Ourtter.Inner();

- 內部類的分類:

1.成員內部類(重點)(成員方法)

a.成員內部類不能存在任何static變數或方法,可以訪問外部類的靜態域。
b.成員內部類是依附外部類的,所以只有先建立了外部類才能建立內部類。

(成員內部類不能擁有靜態域,但可以訪問外部靜態域)

class Outter{
    private String name = "test";
    private static int age = 20;
    //-------------------成員內部類----------------
    class Inner{  
    	      //private static int age = 50; 
    	      //成員內部類不能存在static的變數或方法,會報錯:內部類Outter.Inner中的靜態宣告非法。
        public void fun(){
            System.out.println(name); //可以訪問外部類的靜態或者非靜態屬性
            System.out.println(age);
        }
    }
    //------------------------------------------------
}
public class Test{
    public static void main(String[] args){
        Outter.Inner in = new Outter().new Inner();
        in.fun();
    }
}

2.靜態內部類(重點)(靜態方法)

和非靜態內部類相比,靜態內部類沒有指向外部的引用。同時,非靜態內部類不能宣告靜態成員,只有靜態內部類才可以宣告靜態成員。
靜態內部類將自動轉換為頂層類(top-levelclass),即它沒有父類,而且不能引用外部類成員或其他內部類成員。當一個內部類不需要引用外部類成員,只需要隱藏在另一個類中時,可以將該內部類宣告為靜態的。

a.靜態內部類的建立不需要依賴外部類,可以直接建立。

b.靜態內部類不可以使用任何外部類的非static域(包含屬性與方法),但是可以存在自己的成員變數。

3.方法內部類(區域性內部類)

方法內部類定義在外部類的方法中,區域性內部類和成員內部類基本一致,只是作用域不同,方法內部類只能在該方法中被使用。

a.方法內部類不允許使用訪問許可權修飾符 public private protected 均不允許。

b.方法內部類對外部完全隱藏除了建立這個類的方法可以訪問它以外,其他地方均不能訪問。

c.方法內部類如果要想使用方法形參,該形參必須使用final宣告(JDK8將形參變為隱式final宣告)


public class Test{
    public static void main(String[] args){
        final int i = 8;
        class person{
            public String name;
            public void show(){
                System.out.println(i);
                System.out.println(this.name);
            }
        }
        person p = new person();
        p.name = "zhangsan";
        p.show();
    }
}
程式執行結果:
8
zhangsan

上例中,在main方法中定義了person類,它是一個內部類。內部類方法show訪問了main方法中定義的final型別的區域性變數。其中,方法中內部類只能訪問方法中final型別的區域性變數,而不能訪問其他型別的區域性變數,但可以訪問外部類的資料成員和成員方法。

4.匿名內部類(lamdba表示式前身)

匿名內部類就是一個沒有名字的方法內部類,所以它沒有構造方法(但是如果這個匿名內部類繼承了只含有帶引數構造方法的父類,建立它的時候就必須帶上這些引數,並在實現過程中使用super關鍵字呼叫相應內容)。因此特點與方法內部類完全一樣,除此之外,還有兩個自己的特點:

a.匿名內部類必須繼承一個抽象類或者實現一個介面。

b.匿名內部類沒有構造方法,因為它沒有類名。

匿名類的語法規則:

new interfacename(){...};  或
new superclassname(){...};

總結:內部類的使用暫時不作為設計的首選。

1.破壞了程式的結構。
2.方便進行私有屬性的訪問。(外部類可以訪問內部類的私有域)
3.如果發現類名稱上出現了“ . “,應當立即想到內部類的概念。