Java核心類庫:內(nèi)部類那點(diǎn)事兒
內(nèi)部類:定義在類的內(nèi)部的類
為什么需要內(nèi)部類?
● 典型的情況是,內(nèi)部類繼承自某個(gè)類或?qū)崿F(xiàn)某個(gè)接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對象。所以你可以認(rèn)為內(nèi)部類提供了某種進(jìn)入其外圍類的窗口。
● java中的內(nèi)部類和接口加在一起,可以實(shí)現(xiàn)多繼承。
● 可以使某些編碼根簡潔。
● 隱藏你不想讓別人知道的操作。
使用內(nèi)部類最吸引人的原因是:
每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對于內(nèi)部類都沒有影響。如果沒有內(nèi)部類提供的可以繼 承多個(gè)具體的或抽象的類的能力,一些設(shè)計(jì)與編程問題就很難解決。從這個(gè)角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內(nèi)部類有效 地實(shí)現(xiàn)了“多重繼承”。
內(nèi)部類分為: 成員內(nèi)部類、靜態(tài)嵌套類、方法內(nèi)部類、匿名內(nèi)部類。
特點(diǎn):
一、內(nèi)部類仍然是一個(gè)獨(dú)立的類,在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,但是前面冠以外部類的類命和$符號。
二、內(nèi)部類可以直接或利用引用訪問外部類的屬性和方法,包括私有屬性和方法(但靜態(tài)內(nèi)部類不能訪問外部類的非靜態(tài)成員變量和方法)。內(nèi)部類所訪問的外部屬性的值由構(gòu)造時(shí)的外部類對象決定。
三、而外部類要訪問內(nèi)部類的成員,則只能通過引用的方式進(jìn)行,可問內(nèi)部類所有成員
四、訪問機(jī)制:
|
五、內(nèi)部類可以使用任意的范圍限定:public/private/protected class InnerClass,且嚴(yán)格按照這幾種訪問權(quán)限來控制內(nèi)部類能使用的范圍。普通類的范圍限定只可以是public或者不加。
六、內(nèi)部類的命名不允許與外部類 重名,內(nèi)部類可以繼承同級的內(nèi)部類,也可繼承其它類(除內(nèi)部類和外部類)。
七、內(nèi)部類可以定義為接口,并且可以定義另外一個(gè)類來實(shí)現(xiàn)它
八、內(nèi)部類可以定義為抽象類,可以定義另外一個(gè)內(nèi)部類繼承它
九、內(nèi)部類使用static修飾,自動(dòng)升級為頂級類,外部類不可以用static修飾,用OuterClass.InnerClass inner=new OuterClass.InnerClass();創(chuàng)建實(shí)例。內(nèi)部類還可定義為final.
十、內(nèi)部類可以再定義內(nèi)部類(基本不用)
十一、方法內(nèi)的內(nèi)部類:
方法內(nèi)的內(nèi)部類不能加范圍限定(protected public private)
方法內(nèi)的內(nèi)部類不能加static修飾符
方法內(nèi)的內(nèi)部類只能在方法內(nèi)構(gòu)建其實(shí)例
方法內(nèi)的內(nèi)部類如果訪問方法局部變量,則此局部變量必須使用final修飾
1)靜態(tài)內(nèi)部類(靜態(tài)嵌套類)
從技術(shù)上講,靜態(tài)嵌套類不屬于內(nèi)部類。因?yàn)閮?nèi)部類與外部類共享一種特殊關(guān)系,更確切地說是對實(shí)例的共享關(guān)系。而靜態(tài)嵌套類則沒有上述關(guān)系。它只是位置在另一個(gè)類的內(nèi)部,因此也被稱為頂級嵌套類。
靜態(tài)的含義是該內(nèi)部類可以像其他靜態(tài)成員一樣,沒有外部類對象時(shí),也能夠訪問它。靜態(tài)嵌套類不能訪問外部類的成員和方法。
|
2)成員內(nèi)部類
* 1 成員內(nèi)部類必須利用外部類實(shí)例創(chuàng)建
* 2 成員內(nèi)部類可以共享外部類的實(shí)例變量
|
3)局部內(nèi)部類(方法內(nèi)部類)
(1)方法內(nèi)部類只能在定義該內(nèi)部類的方法內(nèi)實(shí)例化,不可以在此方法外對其實(shí)例化。
(2)方法內(nèi)部類對象不能使用該內(nèi)部類所在方法的非final局部變量。
因?yàn)榉椒ǖ木植孔兞课挥跅I希淮嬖谟谠摲椒ǖ纳趦?nèi)。當(dāng)一個(gè)方法結(jié)束,其棧結(jié)構(gòu)被刪除,局部變量成為歷史。但是該方法結(jié)束之后,在方法內(nèi)創(chuàng) 建的內(nèi)部類對象可能仍然存在于堆中!例如,如果對它的引用被傳遞到其他某些代碼,并存儲(chǔ)在一個(gè)成員變量內(nèi)。正因?yàn)椴荒鼙WC局部變量的存活期和方法內(nèi)部類對 象的一樣長,所以內(nèi)部類對象不能使用它們。用法
|
4)匿名內(nèi)部類
顧名思義,沒有名字的內(nèi)部類。表面上看起來它們似乎有名字,實(shí)際那不是它們的名字。
匿名內(nèi)部類就是沒有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類?如果滿足下面的一些條件,使用匿名內(nèi)部類是比較合適的:
只用到類的一個(gè)實(shí)例。
● 類在定義后馬上用到。
● 類非常小(SUN推薦是在4行代碼以下)
● 給類命名并不會(huì)導(dǎo)致你的代碼更容易被理解
在使用匿名內(nèi)部類時(shí),要記住以下幾個(gè)原則:
● 匿名內(nèi)部類不能有構(gòu)造方法。
● 匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
● 匿名內(nèi)部類不能是public,protected,private,static。
● 只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例。
● 一個(gè)匿名內(nèi)部類一定是在new的后面,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類。
● 因匿名內(nèi)部類為局部內(nèi)部類,所以局部內(nèi)部類的所有限制都對其生效。
A、繼承式的匿名內(nèi)部類和接口式的匿名內(nèi)部類。
- import java.util.Arrays;
- import java.util.Comparator;
- /**匿名內(nèi)部類 語法*/
- public class AnnInnerClass {
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- Yoo yoo = new Yoo();//創(chuàng)建Yoo的實(shí)例
- Yoo y1 = new Yoo(){};
- //new Yoo(){}創(chuàng)建匿名類實(shí)例
- //匿名類new Yoo(){}是繼承Yoo類,并且同時(shí)創(chuàng)建了對象
- //new Yoo(){}是Yoo的子類型,其中{}是類體(class Body)
- //類體中可以定義任何類內(nèi)的語法,如:屬性,方法,方法重載,方法覆蓋,等
- //子類型沒有名字,所以叫匿名類!
- Yoo y2 = new Yoo(){
- public String toString(){//方法重寫(覆蓋)
- return "y2"; //y2是子類的實(shí)例
- }
- };
- System.out.println(y2);//"y2",調(diào)用了匿名類對象toString()
- //匿名內(nèi)部類可以繼承/實(shí)現(xiàn) 于 類,抽象類,接口等
- //按照繼承的語法,子類型必須實(shí)現(xiàn)所有的抽象方法
- //Xoo x = new Xoo(){};//編譯錯(cuò)誤,沒有實(shí)現(xiàn)方法
- final int b = 5;
- Xoo xoo = new Xoo(){ //是實(shí)現(xiàn)接口,并且創(chuàng)建匿名類實(shí)例,不是創(chuàng)建接口對象
- public int add(int a){//實(shí)現(xiàn)接口中的抽象方法
- return a+b; //要訪問局部變量b,只能訪問final變量
- }
- };
- System.out.println(xoo.add(5));//10,調(diào)用對象的方法
- //Comparator接口也可以使用匿名類的方式
- Comparator<String> byLength = new Comparator<String>(){
- public int compare(String o1,String o2){
- return o1.length()-o2.length();
- }
- };
- String[] names = {"Andy","Tom","Jerry"};
- Arrays.sort(names,byLength);
- System.out.println(Arrays.toString(names));
- //也可以這樣寫,工作中常用
- Arrays.sort(names,new Comparator<String>(){
- public int compare(String o1,String o2){
- return o1.length()-o2.length();
- }
- });
- }
- }
B. 參數(shù)式的匿名內(nèi)部類。
|
構(gòu)造內(nèi)部類對象的方法有:
1、內(nèi)部類在自己所處的外部類的靜態(tài)方法內(nèi)構(gòu)建對象或在另一個(gè)類里構(gòu)造對象時(shí)應(yīng)用如下形式:
(1)
|
(2)
OuterClass.InnerClass in=new OuterClass().new InnerClass(); |
其中OuterClass是外部類,InnerClass是內(nèi)部類。
2、內(nèi)部類在它所在的外部類的非靜態(tài)方法里或定義為外部類的成員變量時(shí),則可用以下方式來構(gòu)造對象:
InnerClass in = new InnerClass(); |
3、如果內(nèi)部類為靜態(tài)類,則可用如下形式來構(gòu)造函數(shù):
OuterClass.InnerClass in = new OuterClass.InnerClass(); |
無需再利用外部類的對象來來構(gòu)造內(nèi)部類對象,如果靜態(tài)內(nèi)部類需要在靜態(tài)方法或其它類中構(gòu)造對象就必須用上面的方式來初始化。