匿名內部類
匿名內部類就是沒有名字的內部類;
注意:
匿名內部類不能定義任何靜態成員、方法。
匿名內部類中的方法不能是抽象的;
匿名內部類必須實現接口或抽象父類的所有抽象方法。
匿名內部類訪問的外部類成員變量或成員方法必須用static修飾;
代碼:
接口
public interface Inner { public String say(); }
抽象類
public abstract class Inner1 implements Inner { }
普通類
public class Inner2 implements Inner { public String say() { return "this is Inner2"; } }
外部類
public class Outer { public static String s1 = "this is s1 in Outer"; public static String s2 = "this is s2 in Outer"; private static String s3 = "this is s3 in Outer"; public void method1(Inner inner) { System.out.println(inner.say()); } private static String method2() { return "this is method2 in Outer"; } public static void main(String[] args) { Outer outer = new Outer(); // 測試1,Inner為接口 outer.method1(new Inner() { String s1 = "this is s1 in Inner"; public String say() { // 外部類和匿名函數類中有同名變量s1 return s1; } }); // 測試2,Inner1為抽象類 outer.method1(new Inner1() { String s2 = "this is s2 in Inner1"; public String say() { // 外部類和匿名函數類中有同名變量s2 return Outer.s2; } }); // 測試3,Inner2為普通類 outer.method1(new Inner2() { public String say() { // 訪問外部類私有變量s3 return s3; } }); // 測試4,Inner2為普通類 outer.method1(new Inner2() { public String say() { // 訪問外部類私有方法method1() return method2(); } }); } }
打印:
this is s1 in Inner this is s2 in Outer this is s3 in Outer this is method2 in Outer
分析:
編譯后自動生成四個文件:Outer$1.class、Outer$2.class、Outer$3.class、Outer$4.class。
Outer.class反編譯(屬性值、方法內容略)
public class jichu.Outer { public static java.lang.String s1; public static java.lang.String s2; private static java.lang.String s3; static {}; public jichu.Outer(); public void method1(jichu.Inner); private static java.lang.String method2(); public static void main(java.lang.String[]); static java.lang.String access$0(); static java.lang.String access$1(); }
Outer$1.class反編譯(經優化、調整)
class Outer$1 implements Inner { String s1 = "this is s1 in Inner"; public String say() { return this.s1; } }
Outer$2.class反編譯(經優化、調整)
class Outer$2 extends Inner1 { String s2 = "this is s2 in Inner1"; public String say() { return Outer.s2; } }
Outer$3.class反編譯(經優化、調整)
class Outer$3 extends Inner2 { public String say() { return Outer.access$0(); } }
Outer$4.class反編譯(經優化、調整)
class Outer$4 extends Inner2 { public String say() { return Outer.access$1(); } }
1、匿名內部類因為沒有類名,可知匿名內部類不能定義構造器。
2、因為在創建匿名內部類的時候,會立即創建它的實例,可知匿名內部類不能是抽象類,必須實現接口或抽象父類的所有抽象方法。
3、匿名內部類會繼承一個父類(有且只有一個)或實現一個接口(有且只有一個),實現父類或接口中所有抽象方法,可以改寫父類中的方法,添加自定義方法。
5、當匿名內部類和外部類有同名變量(方法)時,默認訪問的是匿名內部類的變量(方法),要訪問外部類的變量(方法)則需要加上外部類的類名。
6、從Outer.class反編譯代碼中可看出自動生成了兩個靜態方法:access$0()和access$1(),並在測試3和測試4中通過Outer類名直接調用,這樣實現了內部類對外部類私有成員變量和方法的訪問。可知內部類可以訪問外部類私有變量和方法。
疑問
匿名內部類不能含有static的變量和方法。但是測試發現變量可以被static final修飾,為什么?
主要是因為final類型在編譯期間jvm有優化,常量池會維護這些變量。雖然非靜態內部類不能脫離外部類這個上下文實例化,但是常量池使得final變量脫離了類實例化這個條件,編譯期間便可確定。
總結
1、匿名內部類不能定義任何靜態成員、方法。
2、匿名內部類中的方法不能是抽象的;
3、匿名內部類必須實現接口或抽象父類的所有抽象方法。
4、匿名內部類不能定義構造器;
5、匿名內部類訪問的外部類成員變量或成員方法必須用static修飾;
6、內部類可以訪問外部類私有變量和方法。