/**
* @author wangcheng
* @date 17/12/20
*/
public class Outer {
/*
Outer外部類的反編譯結(jié)果,可以發(fā)現(xiàn)對于私有變量data的訪問實際上是通過access$000()方法進(jìn)行的
public class com.thinkjoy.InnerClass.Outer {
public com.thinkjoy.InnerClass.Outer();
public void local(java.lang.String, java.lang.String);
public static void main(java.lang.String[]);
static int access$000(com.thinkjoy.InnerClass.Outer);
}
static int access$100(com.thinkjoy.InnerClass.Outer);
Code:
0: aload_0
1: getfield #1 // Field data:I
4: ireturn
aload_0: 對static方法來說獲取第一個參數(shù),對非static方法來說是this
getfield: 獲取Outer的data字段
ireturn: 返回int類型
*/
// 為什么內(nèi)部類可以訪問外部類的私有變量?
// 首先,在編譯后,該內(nèi)部類和外部類是兩個獨立的文件Outer.class和Outer$MemberInner.class
// 那么,兩個獨立類怎么可以訪問到自己的成員變量,
// 一種方式是直接在類內(nèi)部--這種顯然是不對的,因為已經(jīng)編譯成兩個類文件了
// 第二種方式是通過該類的對象訪問,但是對象只能訪問可見的成員變量,如protected修飾的變量,只能在同包和子類中通過對象直接訪問,
// 那么怎么訪問private呢?
// 通過查看反編譯文件,得知Outer.class中多出了access$000(Outer)這么一個靜態(tài)方法,這個方法返回值就是data
// 如步驟③,內(nèi)部類直接可以訪問外部類的data,實際執(zhí)行的語句是這樣的 System.out.println(Outer.access$000(this$0));
//
// 對于access$000方法不考慮傳入的外部類實例是否可以在其他類中獲取該實例的私有成員變量
// 訪問修飾符是代碼層面的可見性控制,而access$000是編譯器直接生成的字節(jié)碼,故可以訪問
private int data = 0;
static String str = "www";
//成員內(nèi)部類,訪問修飾符可以是private,protected,default,public
class MemberInner {
//static int i = 0; 不能有static局部變量,因為成員內(nèi)部類要在外部類實例創(chuàng)建之后才能創(chuàng)建,當(dāng)內(nèi)部類為講臺局部內(nèi)部類的時候是可以的
private int count = 0;
/*
class com.thinkjoy.InnerClass.Outer$MemberInner {
final com.thinkjoy.InnerClass.Outer this$0;
com.thinkjoy.InnerClass.Outer$MemberInner(com.thinkjoy.InnerClass.Outer);
void print();
static int access$000(com.thinkjoy.InnerClass.Outer$MemberInner);
Code:
0: aload_0
1: getfield #1 // Field count:I
4: ireturn
}
*/
/*
Outer.MemberInner memberInner = new Outer().new MemberInner() {
//nothing to do
};
memberInner.print();
當(dāng)在其他類中進(jìn)行執(zhí)行上述代碼,不會輸出任何東西,
*/
void print() {
//③可以訪問外部類的私有變量
System.out.println(data);
System.out.println(str);
}
class InnerMemberInner{
/*
class com.thinkjoy.InnerClass.Outer$MemberInner$InnerMemberInner {
final com.thinkjoy.InnerClass.Outer$MemberInner this$1;
com.thinkjoy.InnerClass.Outer$MemberInner$InnerMemberInner(com.thinkjoy.InnerClass.Outer$MemberInner);
void innerPrint();
Code:
0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
3: aload_0
4: getfield #1 // Field this$1:Lcom/thinkjoy/InnerClass/Outer$MemberInner;
7: invokestatic #4 // Method com/thinkjoy/InnerClass/Outer$MemberInner.access$000:(Lcom/thinkjoy/InnerClass/Outer$MemberInner;)I
10: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
13: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
16: aload_0
17: getfield #1 // Field this$1:Lcom/thinkjoy/InnerClass/Outer$MemberInner;
20: getfield #6 // Field com/thinkjoy/InnerClass/Outer$MemberInner.this$0:Lcom/thinkjoy/InnerClass/Outer;
23: invokestatic #7 // Method com/thinkjoy/InnerClass/Outer.access$100:(Lcom/thinkjoy/InnerClass/Outer;)I
26: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
29: return
}
*/
void innerPrint(){
System.out.println(count);
System.out.println(data);
}
}
}
//局部內(nèi)部類,不允許有修飾符,類似局部變量
public void local(final String name, String age) {
//①定義在代碼塊中,只能在代碼塊中訪問
//{
// class LocalInner1 {
//
// }
//}
//②編譯報錯,找不到該類的符號
//new LocalInner(){
//
//};
//定義在方法中,可以在方法中訪問,且實例化的代碼必須在定義之后,否則無法訪問,同②
class LocalInner {
/*
該局部內(nèi)部類的
class com.thinkjoy.InnerClass.Outer$1LocalInner {
final java.lang.String val$name;
final com.thinkjoy.InnerClass.Outer this$0;
com.thinkjoy.InnerClass.Outer$1(com.thinkjoy.InnerClass.Outer, java.lang.String);
public void print();
}
*/
public void print() {
// name是外部類local方法的參數(shù),且name必須為final,
// 為什么需要是final?
// 可以發(fā)現(xiàn),上面的注釋是該局部內(nèi)部類的反編譯代碼,
// 發(fā)現(xiàn)編譯器將該類重新生成一個單獨的Outer$1LocalInner類,與Outer同包,
// 在該類中,編譯器新增了一個final的成員變量val$name,也就是Outer的local參數(shù)name的備份,
// 假如local的name不是final的,也就是name是可以更改的,那么是不是局部內(nèi)部類中的val$name也需要做修改
// 所以,編譯器規(guī)定,local的name是final的,不可修改,val$name也就是final(因為name不會變了)
System.out.println(name);
}
}
//匿名內(nèi)部類,沒有名字的內(nèi)部類,其實是繼承Outer$1LocalInner類,編譯器生成的默認(rèn)名字是Outer$1
LocalInner localInner = new LocalInner() {
/*
該匿名內(nèi)部類的
class com.thinkjoy.InnerClass.Outer$1 extends com.thinkjoy.InnerClass.Outer$1LocalInner {
final java.lang.String val$name;
final com.thinkjoy.InnerClass.Outer this$0;
//包可見的構(gòu)造方法,可以設(shè)置外部類的引用this$0與外部類local方法參數(shù)name的備份
com.thinkjoy.InnerClass.Outer$1(com.thinkjoy.InnerClass.Outer, java.lang.String);
public void print();
}
*/
@Override
public void print() {
//name是外部類local方法的參數(shù),且name必須為final
System.out.println(name);
System.out.println(data);
}
};
localInner.print();
}
//嵌套內(nèi)部類--staic修飾的內(nèi)部類
static class StaticInner {
//可以有靜態(tài)的成員變量,并且可以有修飾符
private static int data = 0;
}
public static void main(String[] args) {
// ①成員內(nèi)部類的修飾符為private,在當(dāng)前類中是可以訪問內(nèi)部類的,但是在其他類中是不能訪問內(nèi)部類的
// 同理,其他訪問修飾符是跟成員變量的修飾符的作用是一樣的
MemberInner memberInner = new Outer().new MemberInner();
//②嵌套內(nèi)部類
// System.out.println(StaticInner.data);//可以直接訪問,并且可以根據(jù)修飾符調(diào)整可見性
}
}
java內(nèi)部類
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門医吊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钱慢,“玉大人,你說我怎么就攤上這事卿堂√沧郑” “怎么了?”我有些...
- 文/不壞的土叔 我叫張陵御吞,是天一觀的道長麦箍。 經(jīng)常有香客問我,道長陶珠,這世上最難降的妖魔是什么挟裂? 我笑而不...
- 正文 為了忘掉前任,我火速辦了婚禮揍诽,結(jié)果婚禮上诀蓉,老公的妹妹穿的比我還像新娘栗竖。我一直安慰自己,他們只是感情好渠啤,可當(dāng)我...
- 文/花漫 我一把揭開白布狐肢。 她就那樣靜靜地躺著,像睡著了一般沥曹。 火紅的嫁衣襯著肌膚如雪份名。 梳的紋絲不亂的頭發(fā)上,一...
- 文/蒼蘭香墨 我猛地睜開眼琉兜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毙玻?” 一聲冷哼從身側(cè)響起呕童,我...
- 正文 年R本政府宣布陆盘,位于F島的核電站普筹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏隘马。R本人自食惡果不足惜太防,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酸员。 院中可真熱鬧蜒车,春花似錦讳嘱、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嬉挡,卻和暖如春钝鸽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棘伴。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 1)首先,用內(nèi)部類是因為內(nèi)部類與所在外部類有一定的關(guān)系患朱,往往只有該外部類調(diào)用此內(nèi)部類鲁僚。所以沒有必要專門用一個Jav...
- 1.成員內(nèi)部類 可以把一個內(nèi)部類看做一個成員。成員內(nèi)部類可以無條件訪問外部類的所有成員屬性和成員方法裁厅。 當(dāng)成員內(nèi)部...
- 匿名內(nèi)部類 ;顧名思義,匿名內(nèi)部類是沒有名字的類,并且適用于只想創(chuàng)建一個 子類對象優(yōu)點:書寫格式簡單弊端:只能用...
- 局部內(nèi)部類是定義在函數(shù)的內(nèi)部,不可以用訪問修飾符修飾,只能在函數(shù)內(nèi)部使用,隨著函數(shù)的調(diào)用而使用,只能在該函數(shù)中實例...