java嵌套类型 无法隐藏外层类型_java内部类深入详解 内部类的分类 特点 定义方式 使用...
java內(nèi)部類 內(nèi)部類的分類 特點? 定義方式 使用? ?外部類調(diào)用內(nèi)部類 多層嵌套內(nèi)部類? 內(nèi)部類訪問外部類屬性? 接口中的內(nèi)部類? 內(nèi)部類的繼承? 內(nèi)部類的覆蓋? 局部內(nèi)部類 成員內(nèi)部類 靜態(tài)內(nèi)部類 匿名內(nèi)部類
內(nèi)部類定義
將一個類定義放到另一個類的內(nèi)部,這就是內(nèi)部類
內(nèi)部類與組合是完全不同的概念
內(nèi)部類指的是類的定義在內(nèi)部
看起來像一種代碼隱藏機制
但是,遠不止于此,因為他了解外部類 并且能夠通信
內(nèi)部類的代碼,可以操作創(chuàng)建它的外部類的對象
所以可以認為內(nèi)部類提供了某種進入其外部類的窗口
內(nèi)部類特點
內(nèi)部類訪問外部類不需要任何特殊條件,擁有外部類所有的訪問權(quán)
也就是對于內(nèi)部類訪問外部類的元素這件事情上
他就相當于是外部類本身一樣隨便訪問
內(nèi)部類的創(chuàng)建依賴外部類對象
可以直接訪問外部類的變量
也可以直接指明
外部類類名.this.變量名
this通常是多余的,可以省略
內(nèi)部類不僅能夠訪問包含他的外部類,還可以訪問局部變量
但是局部變量必須被聲明為final
因為局部內(nèi)部類會將調(diào)用的變量進行拷貝,為了保證一致性,所以變量必須為final
內(nèi)部類就是隱匿在外部類內(nèi)部的一個獨立的個體,不存在is a? like a
內(nèi)部類的對象必定秘密的捕獲了一個指向外部類對象的引用
然后以此訪問外部類的成員,編譯器處理了所有的細節(jié),對我們來說都是透明的
public?class?O?{????
class?I{
O?get()?{????????????return?O.this;
}
}
public?static?void?main(String[]?args)?{
O?outer?=?new?O();
O.I?inner?=?outer.new?I();
System.out.println(outer?==?inner.get());
}
}
打印結(jié)果為:true
內(nèi)部類持有的外部類對象就是外部類對象本身,內(nèi)存地址是相同的
外部類的作用域之外,可以使用? outerClass.innerClass? 方式引用內(nèi)部類
可以對同一個包中其他類隱藏
內(nèi)部類可以聲明為私有的
每個類都會產(chǎn)生一個.class文件,包含了類的元信息
如果內(nèi)部類是匿名的,編譯器會簡單的產(chǎn)生一個數(shù)字作為標識符形如 Outer$1.class
否則就是形如? 外部類$內(nèi)部類.class?? ,虛擬機看來與其他類無差,這也是編譯器做的工作
普通的類(外部類)只能用public修飾符修飾,或者不寫修飾符 使用默認的,但是內(nèi)部類可以使用private 與protected
內(nèi)部類可以達到類似"多重繼承"的效果,
每個內(nèi)部類都能獨立的繼承自一個(接口的)實現(xiàn)
無論外部類是否已經(jīng)繼承了某個(接口的)實現(xiàn)
也就是說 單個外部類,可以讓多個內(nèi)部類以不同的方式實現(xiàn)同一個接口或者繼承同一個類
一個外部類可以創(chuàng)建多個內(nèi)部類,這是不是就達到了類似"多重繼承"的效果呢
內(nèi)部類分類成員內(nèi)部類
局部內(nèi)部類
匿名內(nèi)部類
靜態(tài)內(nèi)部類
成員內(nèi)部類
成員內(nèi)部類也叫實例內(nèi)部類。每一個外部類對象都需要一個內(nèi)部類的實例,內(nèi)部類離不開外部類存在
既然是成員內(nèi)部類,和成員屬性成員方法地位上自然沒有什么不同
每個外部類對象都有一個內(nèi)部類對象,自然持有外部類的引用Outer?outer?=?new?Outer();
Outer.Inner?inner?=?outer.new?Inner();//注意是對象.new
局部內(nèi)部類
局部內(nèi)部類不能用public或者private或者protected訪問說明符,作用域被限定在了聲明這個局部內(nèi)部類中了
很好理解,局部的就跟方法變量一樣,限定在了{}之中,自然就不需要設置訪問說明符了,而且你可以想下,也只有類以及類的成員有訪問修飾符,局部變量有訪問修飾符么
局部類可以對外面完全的隱藏起來,即使是外部類的其他的代碼也不能訪問他
局部內(nèi)部類雖然被限定在局部代碼塊{} 里面,但是他也是可以訪問外部類的屬性的,不要被分類迷惑了
匿名內(nèi)部類
匿名內(nèi)部類就是局部內(nèi)部類的進一步隱藏,局部內(nèi)部類定義了之后在局部區(qū)域內(nèi)仍舊可以創(chuàng)建多個對象
匿名內(nèi)部類聲明一個類之后就只能創(chuàng)建一個對象了,因為他并沒有類名字
形式為:new?xxxClass??(){????//或者new?xxxInterface()//.......}
表示創(chuàng)建一個類的對象,這個類是xxxClass? 子類或者實現(xiàn)了xxxInterface 接口的類
也可以說匿名內(nèi)部類就是創(chuàng)建了一個匿名類的子類對象
構(gòu)造方法名字和類名是相同的,匿名內(nèi)部類顯然是沒有構(gòu)造方法的,因為連名字都沒有
既然沒有構(gòu)造方法想要構(gòu)造參數(shù),就只能把參數(shù)傳遞給外部的構(gòu)造器,通過外部類的構(gòu)造器繞一圈,本身內(nèi)部類可以訪問外部類所有的屬性,去把值操作起來
當然外部類自然可以搞點屬性根據(jù)業(yè)務邏輯單獨給內(nèi)部類用
如果是實現(xiàn)接口,不能帶任何的參數(shù)的,因為接口都沒有構(gòu)造方法的呀
不過還可以通過初始化代碼塊達到類似的初始化效果,想必大家還記得初始化代碼塊是什么吧
不過也僅僅是達到類似的效果,而且,相當于只有一個"構(gòu)造方法",因為即使你寫了多個初始化代碼塊,還不是構(gòu)造對象的時候一起執(zhí)行嘛
小技巧,匿名內(nèi)部類的參數(shù)傳遞fun(new?ArrayList(){{add("a");add("b");add("c");}});也就是:
fun(new?ArrayList(){????
{
add("a");
add("b");
add("c");
}
}
);
構(gòu)造了一個匿名內(nèi)部類,內(nèi)部類沒有更新重寫增加任何的方法
設置了一個初始化塊? {}? ,初始化塊會在每個對象構(gòu)造的時候執(zhí)行
代碼塊中調(diào)用add方法增加對象
靜態(tài)內(nèi)部類
如果使用內(nèi)部類只是為了將一個類隱藏到一個類的內(nèi)部
并不需要內(nèi)部類引用外部類的對象
可以將內(nèi)部類聲明為static,以便取消產(chǎn)生的引用
也只有內(nèi)部類可以聲明為static
靜態(tài)內(nèi)部類的對象除了沒有對生成他的外部類的對象的引用特權(quán)外,其他的內(nèi)部類一樣
通過? 外部類 . 內(nèi)部類?? 來訪問
剛才已經(jīng)說了顯然,靜態(tài)內(nèi)部類不會持有外部類的引用
靜態(tài)的創(chuàng)建形式:
Outer.Inner?inner?=?new?Outer.Inner();
內(nèi)部類的繼承
內(nèi)部類的構(gòu)造器必須連接到指向外部類對象的引用
但是在繼承的時候
那個指向外部類對象的"隱匿的"引用必須被初始化
而在派生類中不再存在可連接的默認對象
所以你要解決這個問題,否則的話就會出錯
說的就是要包含指向外部類的引用
必須是帶參數(shù)的,而且參數(shù)類型是外部類 在這里面調(diào)用super
public?class?InnerInherit?extends?OutClass.Inner?{
InnerInherit(OutClass?out){
out.super();
}????public?static?void?main(String[]?args){
OutClass?out?=?new?OutClass();
InnerInherit?ii?=?new?InnerInherit(out);
}
}class?OutClass?{????class?Inner{
}
}
可以看得到,雖然只是繼承內(nèi)部類
但是想要生成一個構(gòu)造器,不僅僅是需要傳遞一個外部類的引用
必須在構(gòu)造器中使用:
enclosingClassReference.super();
說白了就是,內(nèi)部類的對象依賴外部類的對象
內(nèi)部類的子類的對象,也仍舊是依賴外部類的對象的
內(nèi)部類的加載時機
package?test.b;public?class?Outer?{
Outer(){
System.out.println("Outer構(gòu)造方法");
}
{
System.out.println("Outer初始化代碼塊");
}?????static{
System.out.println("Outer靜態(tài)代碼塊");
}
class?Inner{
Inner(){
System.out.println("Inner構(gòu)造方法");
}
{
System.out.println("Inner初始化代碼塊");
}
}
public?static?void?main(String[]?args)?{
Outer?outer?=?new?Outer();
System.out.println("----------");?????????//Outer.Inner?inner?=?outer.new?Inner();
}
}
打印結(jié)果:Outer靜態(tài)代碼塊
Outer初始化代碼塊
Outer構(gòu)造方法
----------
顯然,內(nèi)部類沒有被初始化,放開注釋
打印結(jié)果:Outer靜態(tài)代碼塊
Outer初始化代碼塊
Outer構(gòu)造方法
----------
Inner初始化代碼塊
Inner構(gòu)造方法
所以可以說內(nèi)部類是懶加載的 用到了才加載初始化
而且,可以創(chuàng)建多個內(nèi)部類的實例Outer.Inner?inner1?=?outer.new?Inner();
Outer.Inner?inner2?=?outer.new?Inner();
Outer.Inner?inner3?=?outer.new?Inner();
Outer.Inner?inner4?=?outer.new?Inner();
這是可以的,完全沒問題,每個實例有自己的狀態(tài)信息,與外部類對象信息獨立
內(nèi)部類的覆蓋情況
兩個類之間的繼承和他們各自的內(nèi)部類沒有關(guān)系,不存在覆蓋的情況
兩個類之間的繼承關(guān)系? 比如? B extends A? ,每個類中都有C這個內(nèi)部類
他們兩者中的C是沒有什么關(guān)系的
示例:
類A? 擁有內(nèi)部類C 并且有一個C的對象,構(gòu)造方法中初始化
類B繼承A,并且B中也有一個內(nèi)部類C
public?class?A?{????private?C?c;
A(){
System.out.println("A??constructor");
c?=?new?C();
}
protected?class?C{
C(){
System.out.println("A?....C??constructor");
}
}
public?static?void?main(String[]?args)?{
}
}public?class?B?extends?A{
B(){
System.out.println("B??constructor");
}?????class?C{
C(){
System.out.println("B?....C??constructor");
}
}
public?static?void?main(String[]?args)?{????????new?B();
}
}
創(chuàng)建類B new B();
打印信息:A? constructor
A ....C? constructor
B? constructor
創(chuàng)建B的對象,需要調(diào)用父類的構(gòu)造方法
所以會打印A? constructor? 然后構(gòu)造方法中創(chuàng)建C對象,然后是A ....C? constructor?? 顯然,這并不是B類中的C
所以說:
兩個類之間的繼承,不存在內(nèi)部類被覆蓋的情況
雖然B繼承了A? A有C? B也有C
但是兩個內(nèi)部類是完全獨立的兩個實體
各自在各自的命名空間中
上面的例子中創(chuàng)建一個對象,有父類,調(diào)用父類的構(gòu)造方法,父類的構(gòu)造方法調(diào)用父類的C的構(gòu)造方法,也找不到任何方法會要調(diào)用子類的C
主函數(shù)修改下:
public?static?void?main(String[]?args)?{????//new?B();
A?a?=?new?B();
System.out.println("#############");
B?b?=?new?B();
System.out.println("#############");
a.new?C();
System.out.println("#############");
b.new?C();
System.out.println("#############");
}
打印結(jié)果為:A? constructor
A ....C? constructor
B? constructor
#############
A? constructor
A ....C? constructor
B? constructor
#############
A ....C? constructor
#############
B ....C? constructor
#############
上面兩段很正常,都是創(chuàng)建B對象,自然步驟一樣
當創(chuàng)建a.new C(); 的時候使用的是A的C
當創(chuàng)建b.new C(); 的時候使用的是B的C
顯然,
創(chuàng)建內(nèi)部類對象時,到底是父類中的還是子類中的
是由:??.new 前面的類型決定的,也就是定義的類型,而不是實際指向的類型
多層嵌套的內(nèi)部類
多層嵌套的內(nèi)部類,他能透明的訪問所有他所嵌入的外圍類的所有成員
public?class?NestedClass?{????private?String?NestedClassName?=?"NestedClass";?????
public?class?NestedClass1{?????????private?String?NestedClass1Name?=?"NestedClass1";????????public?class?NestedClass2{?????????????private?String?NestedClass2Name?=?"NestedClass2";????????????public?class?NestedClass3{?????????????????public?void?print()?{
System.out.println("NestedClassName:???"+NestedClassName);
System.out.println("NestedClass1Name:???"+NestedClass1Name);
System.out.println("NestedClass1Name:???"+NestedClass2Name);
}
}
}
}?????public?static?void?main(String[]?args)?{
NestedClass?nestedClass?=?new?NestedClass();
NestedClass.NestedClass1?nestedClass1?=?nestedClass.new?NestedClass1();
NestedClass.NestedClass1.NestedClass2?nestedClass2?=?nestedClass1.new?NestedClass2();
NestedClass.NestedClass1.NestedClass2.NestedClass3?nestedClass3?=?nestedClass2.new?NestedClass3();
nestedClass3.print();
}
}
打印信息NestedClassName:?? NestedClass
NestedClass1Name:?? NestedClass1
NestedClass1Name:?? NestedClass2
從代碼中可以看的出來,多層內(nèi)部類和一層內(nèi)部類創(chuàng)建格式是一樣的
外部類名.內(nèi)部類名 對象名 = 外部類對象.new 內(nèi)部類名();
這個外部類指的就是他的外部,如果他的外部仍舊是別人的內(nèi)部類,那就依次往外找就好了
從打印信息可以看得出來,不管有幾層,內(nèi)部類,可以訪問到他外面的所有的類的屬性信息
接口中的內(nèi)部類
一般情況下
接口中不允許放置任何代碼,但是嵌套類可以作為接口的一部分
你放到接口中的任何類都自動的是public 和 是 static 的
因為類是static,只是將嵌套類置于接口的命名空間內(nèi),并不違反接口的規(guī)則
你甚至可以接口中的內(nèi)部類實現(xiàn)外部接口
如果你想要創(chuàng)建某些公共代碼,使得他們可以被某個接口的所有不同實現(xiàn)所共用
那么使用接口內(nèi)部的嵌套類會顯得很方便
示例:
public?class?Test?{????public?static?void?main(String[]?args)?{?????????//?接口中的內(nèi)部類都是默認?public?static?的
Fly?bird?=?new?Fly.DemoFly();
bird.fly();
Fly?bigBird?=?new?BigBird();
bigBird.fly();
}
}interface?Fly?{????public?void?fly();????class?DemoFly?implements?Fly?{
@Override?????????public?void?fly()?{
System.out.println("一般的鳥都這么飛~");
}
}
}class?BigBird?implements?Fly?{
@Override?????public?void?fly()?{
System.out.println("大鳥都這么飛~");
}
}
打印信息:一般的鳥都這么飛~
大鳥都這么飛~
可以看得出來,直接通過內(nèi)部類,接口的靜態(tài)內(nèi)部類,可以提供一個默認的實現(xiàn)
這就是提供了編程接口的同時,又提供了一個默認的實現(xiàn),多給力
內(nèi)部類中不能有靜態(tài)屬性以及靜態(tài)方法以及靜態(tài)代碼塊class?A{
class?B{????????private?static?int?a=?0;//IDE會提示報錯的??????}
}
非靜態(tài)的內(nèi)部類型,不能聲明靜態(tài)的filed 除非標記為常量,也就是用final聲明
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的java嵌套类型 无法隐藏外层类型_java内部类深入详解 内部类的分类 特点 定义方式 使用...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我的世界怎么设置死亡不掉落
- 下一篇: java迭代器 异常_java迭代器失效