Java常見錯誤-內部類-簡要分析
- 概念
- 分類
- 成員內部類(非靜態內部類)
- 靜態內部類
- 成員內部類和靜態內部類區別
- 局部內部類
- 匿名內部類
- 注意事項
- 總結
概念
? 內部類,顧名思義,就是在一個類的內部定義的類。這種設計允許將一個類的實現細節封裝起來,并可以實現非常緊密的耦合,對于某些特定場景下,比如事件監聽器模型、線程創建等,內部類能提供更加優雅和簡潔的解決方案。
分類
-
成員內部類(非靜態內部類):這是最普通的內部類形式,它作為外部類的一個成員存在,可以直接訪問外部類的成員變量和方法,即使它們是私有的。
-
靜態內部類(靜態嵌套類):靜態內部類與成員內部類的主要區別在于靜態內部類不需要依賴于外部類的實例,它可以通過外部類直接訪問,類似于外部類中的靜態成員。
-
局部內部類:局部內部類是在方法或代碼塊中定義的類,它的作用域僅限于該方法或代碼塊。它可以訪問外部類的成員,同時也可以訪問所在方法的局部變量,但要求這些局部變量必須被聲明為final。
-
匿名內部類:沒有名字的內部類,通常用來創建某個接口的實例或者實現抽象類的一個子類。它可以直接在需要使用的地方創建并實例化,常用于事件處理、線程創建等場景。
成員內部類(非靜態內部類)
public class memberOuterClass {private int data = 5;class InnerClass {void display() {System.out.println("Data from outer class: " + data);}}public static void main(String[] args) {OuterClass outer = new OuterClass();OuterClass.InnerClass inner = outer.new InnerClass();inner.display();}
}
反編譯.class:
public class memberOuterClass {private int data = 5;public memberOuterClass() {}public static void main(String[] var0) {memberOuterClass var1 = new memberOuterClass();InnerClass var2 = var1.new InnerClass();var2.display();}class InnerClass {InnerClass() {}void display() {System.out.println("Data from outer class: " + memberOuterClass.this.data);}}
}
? 可以發現反編譯后的代碼中,外部類和內部類都多了一個無參的構造方法。無論外部類還是內部類,編譯器自動添加默認無參構造函數是為了確保類的可實例化性、支持繼承機制以及維護類實例與其環境的正確關聯
靜態內部類
- 靜態內部類內允許有static屬性、方法;
public class OuterClass {private static int staticData = 10;static class StaticInnerClass {void display() {System.out.println("Static data from outer class: " + staticData);}}public static void main(String[] args) {OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();inner.display();}
}
成員內部類和靜態內部類區別
1、在是否可以使用static修飾上
- 成員內部類內不允許有static屬性、static方法;除非final static存常量池中
2、對外部類的引用及互相訪問上
非靜態成員內部類
:可以直接訪問外部類的所有成員(包括靜態和非靜態),因為它持有一個隱式的外部類實例的引用(通常稱為this$0)。這意味著非靜態內部類的實例化必須在外部類的實例上下文中進行。- ``靜態成員內部類`:不持有對外部類實例的直接引用,因此它不能直接訪問外部類的非靜態成員變量和方法 。它可以訪問外部類的靜態成員(包括靜態字段和方法),因為靜態成員屬于類本身,不依賴于類的實例進行創建。
3、內部類創建上
- 靜態內部類
public class Outer {public static class StaticInner {public void show() {System.out.println("靜態內部類");}}
}// 使用靜態內部類,無需創建Outer實例
Outer.StaticInner inner = new Outer.StaticInner();
inner.show();
- 成員內部類
public class Outer {public class MemberInner {public void show() {System.out.println("成員內部類");}}
}// 使用成員內部類,需先創建Outer實例
Outer outer = new Outer();
Outer.MemberInner inner = outer.new MemberInner();
inner.show();
小結:靜態內部類的實例化不需要外部類的實例。成員內部類的實例化需要先有外部類的實例,并通過外部類實例來創建內部類實例。
4、一個外部類內多個成員內部類分別繼承不同父類,實現"多繼承"
public class Outer {// 第一個內部類繼承自類Apublic class InnerA extends A {// InnerA 的實現}// 第二個內部類繼承自類Bpublic class InnerB extends B {// InnerB 的實現}public static void main(String[] args) {// 創建 InnerA 和 InnerB 的實例InnerA innerA = new Outer().new InnerA();InnerB innerB = new Outer().new InnerB();}
}
局部內部類
public class OuterClass {void someMethod() {final int localData = 7;class LocalInnerClass {void show() {System.out.println("Local data: " + localData);}}LocalInnerClass local = new LocalInnerClass();local.show();}public static void main(String[] args) {OuterClass outer = new OuterClass();outer.someMethod();}
}
注:局部內部類就像是方法里面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。
匿名內部類
import java.util.ArrayList;
import java.util.List;public class Test {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("Hello");list.add("World");list.forEach(new java.util.function.Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});// 或者使用Lambda表達式簡化(也是匿名內部類的一種體現)list.forEach(s -> System.out.println(s));}
}
? 匿名內部類是一種特殊的類,它不具備明確的構造器,這限制了它的應用場景。主要用途是作為接口的簡短實現,尤其是用作回調機制。在編譯時,它會被系統自動生成一個類似于Outer$1.class的名稱。通常,匿名內部類用于擴展已有類或實現接口,并專注于提供必要的方法實現,而不涉及額外的功能。
注意事項
//TODO
總結
? 內部類是Java語言提供的一種特殊類,它允許類定義嵌套在其他類中,這為程序設計提供了更大的靈活性。不同類型的內部類有著不同的應用場景和訪問規則,如成員內部類用于需要訪問外部類非靜態成員的情況,靜態內部類更像一個獨立的類但邏輯上屬于外部類,局部內部類和匿名內部類則常用于臨時性需求,如事件處理或實現特定接口的簡短實現。理解并恰當使用內部類,可以使代碼更加清晰、高效和易于維護。