1. 程式人生 > >java內部類總結 問題:內部類、靜態內部類區別、使用場景?

java內部類總結 問題:內部類、靜態內部類區別、使用場景?

問題:內部類、靜態內部類區別、使用場景?

1.靜態內部類可以有靜態成員(方法,屬性),而非靜態內部類則不能有靜態成員(方法,屬性)。
2.靜態內部類只能夠訪問外部類的靜態成員,而非靜態內部類則可以訪問外部類的所有成員(方法,屬性)。
3.例項化方式不同:
(1)例項化成員內部類“”
通過外部類物件建立
OutClassTest oc1 = new OutClassTest();
OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();
(2)例項化靜態內部類:
OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass();

3.訪問內部類成員屬性不同:
(1)外部類訪問內部類屬性和方法:
外部類可以通過內部類引用間接訪問內部類元素 類似:new IN().inMessage()
(2)外部類訪問靜態內部類:
呼叫內部靜態類的方法或靜態變數,通過類名直接呼叫
OutClassTest.InnerStaticClass.static_value
OutClassTest.InnerStaticClass.getMessage()
6.為何要用內部類?

  1. 內部類可以訪問外部類的所有成員,包括私有屬性。
  2. 方便將存在一定邏輯關係的類組織在一起,又可以對外界隱藏。
  3. 每個內部類都能獨立地繼承一個介面,而無論外部類是否已經繼承了某個介面。因此,內部類使多重繼承的解決方案變得更加完整。

一、什麼是內部類?(一般)

在一個類Out的內部定義一個類in,這個類就是內部類,相應的Out就成為外部類。

二、內部類與外部類的聯絡

1、內部類是一個編譯時概念,編譯後外部類及其內部類會生成兩個獨立的class檔案: OuterClass.class和OuterClass$InnerClass.class

2、內部類可以直接訪問外部類的元素,但是外部類不可以直接訪問內部類的元素

3、外部類可以通過內部類引用間接訪問內部類元素

4、對於靜態內部類來說,靜態內部類是不依賴於外部類的,也就說可以在不建立外部類物件的情況下建立內部類的物件。另外,靜態內部類是不持有指向外部類物件的引用的

三、內部類的分類

成員內部類、區域性內部類、匿名內部類、靜態內部類。

1、成員內部類
成員內部類就是普通的內部類,內部類可以宣告public、protected、private等訪問限制,可以宣告 為abstract的供其他內部類或外部類繼承與擴充套件,或者宣告為static、final的,也可以實現特定的介面。

如果成員內部類用private修飾,則只能在外部類的內部訪問,如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;
如果是預設訪問許可權,則只能在同一個包下訪問。這一點和外部類有一點不一樣,外部類只能被public和包訪問兩種許可權修飾。

外部類按常規的類訪問方式使用內部類,唯一的差別是外部類可以訪問內部類的所有方法與屬性,包括私有方法與屬性。

內部類中的this與其他類一樣是指的本身。建立內部類物件時,它會與創造它的外圍物件有了某種聯絡,於是能訪問外圍類的所有成員,不需任何特殊條件,可理 解為內部類連結到外部類。 用外部類建立內部類物件時,此內部類物件會祕密的捕獲一個指向外部類的引用,於是,可以通過這個引用來訪問外圍類的成員。

2、區域性內部類

區域性內部類是定義在一個方法或者一個作用域裡面的類,它和成員內部類的區別在於區域性內部類的訪問僅限於方法內或者該作用域內。

3、匿名內部類
匿名內部類其實就是一個沒有名字的方法內部類,所以它符合方法內部類的所有約束,初次之外,還有一些地方需要注意:

匿名內部類是沒有訪問修飾符的。
匿名內部類必須繼承一個抽象類或者實現一個介面
匿名內部類中不能存在任何靜態成員或方法
匿名內部類是沒有構造方法的,因為它沒有類名。

一般使用匿名內部類的場景是,要繼承或實現的介面只有一個抽象方法:

程式碼來自[https://www.cnblogs.com/CodingAndRiding/p/7441438.html][1]
 public class Test {
    public static void main(String[] args) {
        //4.匿名內部類
        //主要是針對那些不能直接建立物件的抽象類和介面而來的
        Student stu=new Student();
        System.out.println(stu.getClass());//class com.aowin.noname.Student
        //4.1.通過實體類建立匿名內部類物件
        //相當於建立該類的一個子類物件
        Person p=new Person(){
            public void eat(){
                System.out.println("吃八元套餐");
            }
        };
        p.eat();
        System.out.println(p.getClass());//class com.aowin.noname.Test$1//系統自動為子類命名Test$1
        
        Dog dog=new Dog();
        dog.bark();
        //4.2.通過抽象類建立匿名內部類物件
        //相當於定義了該抽象類的一個子類物件,並重寫了抽象類中所有的抽象方法
        Animal an=new Animal(){
            public void bark(){
                System.out.println("汪汪汪...");
            }
        };
        an.bark();
        //返回的是包名加類名
        System.out.println(an.getClass());//class com.aowin.noname.Test$2
        
        //4.3.通過介面建立匿名內部類物件
        //相當於定義了該介面的一個實現類物件,並重寫了介面中所有的抽象方法
        Sportable s=new Sportable(){
            public void sport(){
                System.out.println("打籃球");
            }
        };
        s.sport();
        System.out.println(s.getClass());//class com.aowin.noname.Test$3
        
    }
}
//實體類
class Person{
    public void eat(){
        System.out.println("吃飯");
    }
}
class Student extends Person{
    public void eat(){
        System.out.println("吃八元套餐");
    }
}
//抽象類
abstract class Animal{
    public abstract void bark();
}
class Dog extends Animal{
    public void bark() {
        System.out.println("汪汪...");
    }
}
//介面
interface Sportable{
    public abstract void sport();
}
4、靜態內部類
關鍵字static可以修飾成員變數、方法、程式碼塊,其實它還可以修飾內部類,使用static修飾的內部類我們稱之為靜態內部類。
靜態內部類與非靜態內部類之間存在一個最大的區別,我們知道非靜態內部類在編譯完成之後會隱含地儲存著一個引用,該引用是指向建立它的外圍內。
但是靜態內部類卻沒有。沒有這個引用就意味著:

靜態內部類的建立是不需要依賴於外圍類,可以直接建立
靜態內部類不可以使用任何外圍類的非static成員變數和方法,而內部類則都可以

    private static String outerName;
    public  int age;

    static class InnerClass1{
        /* 在靜態內部類中可以存在靜態成員 */
        public static String _innerName = "static variable";
        public void display(){
            /*
             * 靜態內部類只能訪問外部類的靜態成員變數和方法
             * 不能訪問外部類的非靜態成員變數和方法
             */
            System.out.println("OutClass name :" + outerName);
        }
    }
    class InnerClass2{
        /* 非靜態內部類中不能存在靜態成員 */
        public String _innerName = "no static variable";
        /* 非靜態內部類中可以呼叫外部類的任何成員,不管是靜態的還是非靜態的 */
        public void display(){
            System.out.println("OuterClass name:" + outerName);
            System.out.println("OuterClass age:" + age);
        }
    }
    public void display(){
        /* 外部類能直接訪問靜態內部類靜態元素 */
        System.out.println(InnerClass1._innerName);
        /* 靜態內部類可以直接建立例項不需要依賴於外部類 */
        new InnerClass1().display();
        /* 非靜態內部的建立需要依賴於外部類 */
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
        /* 非靜態內部類的成員需要使用非靜態內部類的例項訪問 */
        System.out.println(inner2._innerName);
        inner2.display();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.display();
    }
}

四、內部類和外部類的相互訪問

1、內部類訪問外部類成員

當成員內部類擁有和外部類同名的成員變數或者方法時,會發生隱藏現象,即預設情況下訪問的是成員內部類的成員如果要訪問外部類的同名成員,需要以下面的形式進行訪問:

外部類.this.成員變數 
外部類.this.成員方法
但是靜態內部類,只能訪問外部類的靜態成員

2、外部類訪問內部類成員
外部類可以通過內部類引用間接訪問內部類元素

外部類中如果要訪問成員內部類的成員,必須先建立一個成員內部類的物件,再通過指向這個物件的引用來訪問:

外部類訪問內部類:
new In().inMessage();  //必須先建立內部類的物件,再訪問

    class In{     //內部類
        public void inMessage() {
            System.out.println("外部類訪問");  //外部類的private成員
        }
    }  

3、靜態內部類與外部類的訪問(相當於巢狀類)

(1)靜態內部類訪問外部類: 只能訪問外部類的靜態成員,不能訪問非靜態成員!
(2)外部類訪問靜態內部類成員:可以直接訪問,內部類名.屬性(方法)

文章來源:北大青鳥  HD089455