內部類:定義在其他類里面的類。
使用內部類的理由:
1.內部類方法能夠訪問外部類的任何數據成員包括私有成員。
2.對同一個包的其他類,內部類是不可見的。
3.匿名內部類能夠方便的定義回調而不用寫太多代碼。
非靜態內部類沒有默認的構造函數(無參數的),非靜態內部類的構造函數都有一個final的外圍類對象引用this$0。
內部類的特殊語法規則:
1.相對內部類,引用其外部類隱式對象的形式:OuterClass.this
2.調用內部類的構造函數:outerObject.new InnerClass(construction parameters);
3.外部類外面引用內部類:OuterClass.InnerClass
內部類是一種編譯器現象與虛擬機無關。編譯器將內部類翻譯為用$分隔外部類名和內部類名的常規類文件,虛擬機對此并無所知。
使用javap -private OuterClass$InnerClass。javap這個工具確實挺不錯的,對分析字節碼和源碼都有很大的幫助。
可以看出詳細的內部類源碼清單,其中包括了編譯器自動添加的部分:
public class Outer
{
?public class Inner
?{
?}
}
當內部類是非靜態內部類時相應的內部類的詳細源碼如下:
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
??? final Outer this$0;? //編譯器自動在內部類里面添加了指向外部類對象的引用
??? public Outer$Inner(Outer);? //內部類的構造函數默認有一個外部類對象作為參數。
}
當內部類是靜態內部類時:
Compiled from "Outer.java"
public class Outer$Inner extends java.lang.Object{
??? public Outer$Inner(); //沒有了對外部類對象的引用
}
如下代碼模擬了上面內部類的情形唯一不同的是這里的Inner沒有訪問Outer私有數據的權限:
class Outer{
?? Inner in = new Inner(this);
}
class Inner{
?? public Inner(Outer outer){
????? this.outer = outer;
?? }
??
?? private Outer outer;
}
?
//那么權限是如何控制的呢?當內部類中的方法訪問到外部類的私有數據時(注意如果內部類沒有方法去訪問外部類的私有數據不會生成該靜態方法static int access$000(Outer);)
public class Outer
{
?private int i;
?public void methodOne()
?{
?}
?class Inner
?{
??public void print(){
???System.out.println(Outer.this.i);
??}
?}
}
相應的外部類詳細源碼如下:
public class Outer
{
?? public Outer();
?? public void methodOne();
?? static int access$000(Outer); //由編譯器合成的用于內部類對外部類進行特殊訪問權限的控制:這也是
??????????????????????????????? //為什么內部類能夠訪問外部類中的私有數據的原因。
?? private int i;
}
內部類訪問外部類的private數據的這種方式很可能導致危險,雖然access$000不是一個合法的Java方法名,但是熟悉class文件結構的黑客可以使用十六進制編輯器輕松創建一個用虛擬機指令調用那個方法的類文件。由于隱秘的訪問方法需要擁有包可見性,所以攻擊代碼需要與被攻擊類放在同一個包中??傊?,如果內部類訪問了外部類的私有數據域,就有可能通過附加在外部類所在包中的其他類訪問私有數據。
局部內部類:定義在方法之中,因此局部類沒有public和private修飾符。對外界是完全隱藏的。
局部類不僅能夠訪問外部類,還能訪問方法中的局部變量(或方法的參數)。不過那些局部變量要聲明為final的。
匿名內部類:用外部類+$+數字的形式表示。一個外部類中有多個匿名內部類時,其生成的class文件對應有Outer$(1、2、3)的形式表示。注意到該匿名內部類是final的。
final class Outer$1
{
?? Outer$1(Outer);
?? public void method();
?? final Outer this$0;
}
嵌套類:當內部類不需要訪問外部類的數據成員時應該使用嵌套類。注意只有內部類可以聲明為static的其他不行。
在接口中聲明的內部類自動轉換為public static的,在接口中定義的成員自動都是public static的。
內部類構造函數的可見性與其類的可見性相同。當內部類是private時其構造函數也是private的,當內部類是public的其構造函數也是public的。
posted on 2010-04-21 14:57
桔子汁 閱讀(594)
評論(0) 編輯 收藏 所屬分類:
J2SE