java內部類面試總結

本文轉自牛客網上 BlueFish 總結的Java內部類的筆記,我覺得很詳細,在此轉發進行記錄。
有問題大家可以到牛客網進行討論:

1.爲什麼使用內部類?

使用內部類最吸引人的原因是:每個內部類都能獨立地繼承一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。
使用內部類最大的優點就在於:它能夠非常好的解決多重繼承的問題,使用內部類還能夠爲我們帶來如下特性:
(1) 內部類可以用多個實例,每個實例都有自己的狀態信息,並且與其他外圍對象的信息相互獨立。
(2) 在單個外圍類中,可以讓多個內部類以不同的方式實現同一個接口,或者繼承同一個類。
(3) 創建內部類對象的時刻並不依賴於外圍類對象的創建。
(4) 內部類並沒有令人迷惑的“is-a”關係,他就是一個獨立的實體。
(5) 內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問。

2.內部類分類:

(一).成員內部類:

public class Outer{
        private int age = 99;
        String name = "Coco";
        public class Inner{
            String name = "Jayden";
            public void show(){
                System.out.println(Outer.this.name);
                System.out.println(name);
                System.out.println(age);
            }
        }
        public Inner getInnerClass(){
            return new Inner();
        }
        public static void main(String[] args){
            Outer o = new Outer();
            Inner in = o.new Inner();
            in.show();
        }
    }

1 . Inner 類定義在 Outer 類的內部,相當於 Outer 類的一個成員變量的位置,Inner 類可以使用任意訪問控制符,如 public 、 protected 、 private 等。
2. Inner 類中定義的 show() 方法可以直接訪問 Outer 類中的數據,而不受訪問控制符的影響,
如直接訪問 Outer 類中的私有屬性age。
3. 定義了成員內部類後,必須使用外部類對象來創建內部類對象,而不能直接去 new 一個內部類對象,即:內部類 對象名 = 外部類對象.new 內部類( );
4. 編譯上面的程序後,會發現產生了兩個 .class 文件: Outer.class,Outer$Inner.class{}
5. 成員內部類中不能存在任何 static 的變量和方法,但可以定義常量:
(1)因爲非靜態內部類是要依賴於外部類的實例,而靜態變量和方法是不依賴於對象的,僅與類相關,
簡而言之:在加載靜態域時,根本沒有外部類,所在在非靜態內部類中不能定義靜態域或方法,編譯不通過;
非靜態內部類的作用域是實例級別。
(2)常量是在編譯器就確定的,放到所謂的常量池了。

★★友情提示:

1.外部類是不能直接使用內部類的成員和方法的,可先創建內部類的對象,然後通過內部類的對象來訪問其成員變量和方法;
2.如果外部類和內部類具有相同的成員變量或方法,內部類默認訪問自己的成員變量或方法,如果要訪問外部類的成員變量,可以使用 this 關鍵字,如:Outer.this.name

(二).靜態內部類: 是 static 修飾的內部類,

public class Outer{
            private int age = 99;
            static String name = "Coco";
            public static class Inner{
                String name = "Jayden";
                public void show(){
                    System.out.println(Outer.name);
                    System.out.println(name);                  
                }
            }
            public static void main(String[] args){
                Inner i = new Inner();
                i.show();
            }
        }

1 . 靜態內部類不能直接訪問外部類的非靜態成員,但可以通過 new 外部類().成員 的方式訪問
2. 如果外部類的靜態成員與內部類的成員名稱相同,可通過“類名.靜態成員”訪問外部類的靜態成員;如果外部類的靜態成員與內部類的成員名稱不相同,則可通過“成員名”直接調用外部類的靜態成員。
3. 創建靜態內部類的對象時,不需要外部類的對象,可以直接創建 內部類 對象名 = new 內部類();

(三).方法內部類:其作用域僅限於方法內,方法外部無法訪問該內部類

 /*
        使用的形參爲何要爲 final???
         在內部類中的屬性和外部方法的參數兩者從外表上看是同一個東西,但實際上卻不是,所以他們兩者是可以任意變化的,
         也就是說在內部類中我對屬性的改變並不會影響到外部的形參,而然這從程序員的角度來看這是不可行的,
         畢竟站在程序的角度來看這兩個根本就是同一個,如果內部類該變了,而外部方法的形參卻沒有改變這是難以理解
         和不可接受的,所以爲了保持參數的一致性,就規定使用 final 來避免形參的不改變
         */
        public class Outer{
            public void Show(){
                final int a = 25;
                int b = 13;
                class Inner{
                    int c = 2;
                    public void print(){
                        System.out.println("訪問外部類:" + a);
                        System.out.println("訪問內部類:" + c);
                    }
                }
                Inner i = new Inner();
                i.print();
            }
            public static void main(String[] args){
                Outer o = new Outer();
                o.show();
            }
        }    

1.部內部類就像是方法裏面的一個局部變量一樣,是不能有 public、protected、private 以及 static 修飾符的。
2. 只能訪問方法中定義的 final 類型的局部變量,因爲:
當方法被調用運行完畢之後,局部變量就已消亡了。但內部類對象可能還存在,直到沒有被引用時纔會消亡。此時就會出現一種情況,就是內部類要訪問一個不存在的局部變量;當方法被調用運行完畢之後,局部變量就已消亡了。但內部類對象可能還存在,直到沒有被引用時纔會消亡。此時就會出現一種情況,就是內部類要訪問一個不存在的局部變量;
==>使用final修飾符不僅會保持對象的引用不會改變,而且編譯器還會持續維護這個對象在回調方法中的生命週期.
局部內部類並不是直接調用方法傳進來的參數,而是內部類將傳進來的參數通過自己的構造器備份到了自己的內部,
自己內部的方法調用的實際是自己的屬性而不是外部類方法的參數;
防止被篡改數據,而導致內部類得到的值不一致。
3. 注意:
在JDK8版本之中,方法內部類中調用方法中的局部變量,可以不需要修飾爲 final,匿名內部類也是一樣的,主要是JDK8之後增加了 Effectively final 功能在JDK8版本之中,方法內部類中調用方法中的局部變量,可以不需要修飾爲 final,匿名內部類也是一樣的,主要是JDK8之後增加了 Effectively final 功能
http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html
反編譯jdk8編譯之後的class文件,發現內部類引用外部的局部變量都是 final 修飾的.

(四).匿名內部類:

1 .匿名內部類是直接使用 new 來生成一個對象的引用;
2. 對於匿名內部類的使用它是存在一個缺陷的,就是它僅能被使用一次,創建匿名內部類時它會立即創建一個該類的實例,
該類的定義會立即消失,所以匿名內部類是不能夠被重複使用;
3. 使用匿名內部類時,我們必須是繼承一個類或者實現一個接口,但是兩者不可兼得,同時也只能繼承一個類或者實現一個接口;
4. 匿名內部類中是不能定義構造函數的,匿名內部類中不能存在任何的靜態成員變量和靜態方法;
5. 匿名內部類中不能存在任何的靜態成員變量和靜態方法,匿名內部類不能是抽象的,它必須要實現繼承的類或者實現的接口的所有抽象方法
6. 匿名內部類初始化:使用構造代碼塊!利用構造代碼塊能夠達到爲匿名內部類創建一個構造器的效果

 public class OuterClass {
            public InnerClass getInnerClass(final int   num,String str2){
                return new InnerClass(){
                    int number = num + 3;
                    public int getNumber(){
                        return number;
                    }
                };        /* 注意:分號不能省 */
            }
            public static void main(String[] args) {
                OuterClass out = new OuterClass();
                InnerClass inner = out.getInnerClass(2, "chenssy");
                System.out.println(inner.getNumber());
            }
        }
        interface InnerClass {
            int getNumber();
        }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章