Java核心類庫:內(nèi)部類那點事兒
內(nèi)部類:定義在類的內(nèi)部的類
為什么需要內(nèi)部類?
- 典型的情況是,內(nèi)部類繼承自某個類或實現(xiàn)某個接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對象。所以你可以認為內(nèi)部類提供了某種進入其外圍類的窗口。
- java中的內(nèi)部類和接口加在一起,可以實現(xiàn)多繼承。
- 可以使某些編碼根簡潔。
- 隱藏你不想讓別人知道的操作。
使用內(nèi)部類最吸引人的原因是:
每個內(nèi)部類都能獨立地繼承自一個(接口的)實現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(接口的)實現(xiàn),對于內(nèi)部類都沒有影響。如果沒有內(nèi)部類提供的可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決。從這個角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內(nèi)部類有效地實現(xiàn)了“多重繼承”。
內(nèi)部類分為: 成員內(nèi)部類、靜態(tài)嵌套類、方法內(nèi)部類、匿名內(nèi)部類。
特點:
一、內(nèi)部類仍然是一個獨立的類,在編譯之后內(nèi)部類會被編譯成獨立的.class文件,但是前面冠以外部類的類命和$符號。
二、內(nèi)部類可以直接或利用引用訪問外部類的屬性和方法,包括私有屬性和方法(但靜態(tài)內(nèi)部類不能訪問外部類的非靜態(tài)成員變量和方法)。內(nèi)部類所訪問的外部屬性的值由構造時的外部類對象決定。
三、而外部類要訪問內(nèi)部類的成員,則只能通過引用的方式進行,可問內(nèi)部類所有成員
四、訪問機制:
- System.out.println(this.x);或System.out.println(x);//內(nèi)部類訪問內(nèi)部類的成員變量或成員方法可用此方法。
- System.out.println(OuterClass.this.x);//內(nèi)部類訪問外部類的同名變量時可用此方法,如果沒有同名可用System.out.println(x);
五、內(nèi)部類可以使用任意的范圍限定:public/private/protected class InnerClass,且嚴格按照這幾種訪問權限來控制內(nèi)部類能使用的范圍。普通類的范圍限定只可以是public或者不加。
六、內(nèi)部類的命名不允許與外部類 重名,內(nèi)部類可以繼承同級的內(nèi)部類,也可繼承其它類(除內(nèi)部類和外部類)。
七、內(nèi)部類可以定義為接口,并且可以定義另外一個類來實現(xiàn)它
八、內(nèi)部類可以定義為抽象類,可以定義另外一個內(nèi)部類繼承它
九、內(nèi)部類使用static修飾,自動升級為***類,外部類不可以用static修飾,用OuterClass.InnerClass inner=new OuterClass.InnerClass();創(chuàng)建實例。內(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)構建其實例
- 方法內(nèi)的內(nèi)部類如果訪問方法局部變量,則此局部變量必須使用final修飾
1)靜態(tài)內(nèi)部類(靜態(tài)嵌套類)
從技術上講,靜態(tài)嵌套類不屬于內(nèi)部類。因為內(nèi)部類與外部類共享一種特殊關系,更確切地說是對實例的共享關系。而靜態(tài)嵌套類則沒有上述關系。它只是位置在另一個類的內(nèi)部,因此也被稱為***嵌套類。
靜態(tài)的含義是該內(nèi)部類可以像其他靜態(tài)成員一樣,沒有外部類對象時,也能夠訪問它。靜態(tài)嵌套類不能訪問外部類的成員和方法。
語法
- package com.tarena.day13;
- import com.tarena.day13.Foo.Koo;
- /**
- * 靜態(tài)類內(nèi)部語法演示
- */
- public class StaticInner {
- public static void main(String[] args) {
- Koo koo = new Koo();
- System.out.println(koo.add());//4
- }
- }
- class Foo{
- int a = 1;
- static int b = 3;
- /** 靜態(tài)內(nèi)部類,作用域類似于靜態(tài)變量,屬于類的 */
- static class Koo{
- public int add(){
- //a ,不能訪問a
- return b+1;
- }
- }
- }
2)成員內(nèi)部類
* 1 成員內(nèi)部類必須利用外部類實例創(chuàng)建
* 2 成員內(nèi)部類可以共享外部類的實例變量
- import com.tarena.day13.inn.Goo.Moo;
- public class InnerClassDemo {
- public static void main(String[] args) {
- //Moo moo = new Moo(); //編譯錯誤,必須創(chuàng)建Goo的實例
- Goo goo = new Goo();
- Moo moo = goo.new Moo();//利用goo實例創(chuàng)建Moo實例
- Moo moo1 = goo.new Moo();
- //moo和moo1共享同一個goo實例的實例變量
- System.out.println(moo.add());//2
- System.out.println(moo1.add());//2
- Goo goo1 = new Goo();
- goo1.a = 8;
- Moo m1 = goo1.new Moo();
- Moo m2 = goo1.new Moo();
- System.out.println(m1.add());//9
- System.out.println(m2.add());//9
- }
- }
- class Goo{
- int a = 1;
- /**成員內(nèi)部類*/
- class Moo{
- public int add(){
- return a+1;
- }
- }
- }
3)局部內(nèi)部類(方法內(nèi)部類)
(1) 方法內(nèi)部類只能在定義該內(nèi)部類的方法內(nèi)實例化,不可以在此方法外對其實例化。
(2) 方法內(nèi)部類對象不能使用該內(nèi)部類所在方法的非final局部變量。
因為方法的局部變量位于棧上,只存在于該方法的生命期內(nèi)。當一個方法結束,其棧結構被刪除,局部變量成為歷史。但是該方法結束之后,在方法內(nèi)創(chuàng)建的內(nèi)部類對象可能仍然存在于堆中!例如,如果對它的引用被傳遞到其他某些代碼,并存儲在一個成員變量內(nèi)。正因為不能保證局部變量的存活期和方法內(nèi)部類對象的一樣長,所以內(nèi)部類對象不能使用它們。用法
- package com.tarena.day13.inn;
- import java.util.Comparator;
- /**
- * 局部內(nèi)部類
- */
- public class LocalInnerClassDemo {
- public static void main(String[] args) {
- int a = 5;
- final int b = 5;
- //局部內(nèi)部類,定義在方法內(nèi)部,作用域類似于局部變量
- //僅僅在方法內(nèi)部可見
- //在局部內(nèi)部類中可以訪問方法中的局部final變量
- class Foo{
- public int add(){
- return b;//正確
- //return a;//編譯錯誤
- }
- }
- Foo foo = new Foo();
- //臨時的自定義比較規(guī)則
- class ByLength implements Comparator<String>{
- public int compare(String o1,String o2){
- return o1.length()-o2.length();
- }
- }
- }
- }
4)匿名內(nèi)部類
顧名思義,沒有名字的內(nèi)部類。表面上看起來它們似乎有名字,實際那不是它們的名字。
匿名內(nèi)部類就是沒有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類?如果滿足下面的一些條件,使用匿名內(nèi)部類是比較合適的:
只用到類的一個實例。
- 類在定義后馬上用到。
- 類非常?。⊿UN推薦是在4行代碼以下)
- 給類命名并不會導致你的代碼更容易被理解
在使用匿名內(nèi)部類時,要記住以下幾個原則:
- 匿名內(nèi)部類不能有構造方法。
- 匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
- 匿名內(nèi)部類不能是public,protected,private,static。
- 只能創(chuàng)建匿名內(nèi)部類的一個實例。
- 一個匿名內(nèi)部類一定是在new的后面,用其隱含實現(xiàn)一個接口或實現(xiàn)一個類。
- 因匿名內(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的實例
- Yoo y1 = new Yoo(){};
- //new Yoo(){}創(chuàng)建匿名類實例
- //匿名類new Yoo(){}是繼承Yoo類,并且同時創(chuàng)建了對象
- //new Yoo(){}是Yoo的子類型,其中{}是類體(class Body)
- //類體中可以定義任何類內(nèi)的語法,如:屬性,方法,方法重載,方法覆蓋,等
- //子類型沒有名字,所以叫匿名類!
- Yoo y2 = new Yoo(){
- public String toString(){//方法重寫(覆蓋)
- return "y2"; //y2是子類的實例
- }
- };
- System.out.println(y2);//"y2",調(diào)用了匿名類對象toString()
- //匿名內(nèi)部類可以繼承/實現(xiàn) 于 類,抽象類,接口等
- //按照繼承的語法,子類型必須實現(xiàn)所有的抽象方法
- //Xoo x = new Xoo(){};//編譯錯誤,沒有實現(xiàn)方法
- final int b = 5;
- Xoo xoo = new Xoo(){ //是實現(xiàn)接口,并且創(chuàng)建匿名類實例,不是創(chuàng)建接口對象
- public int add(int a){//實現(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();
- }
- });
- }
- }
接口式的匿名內(nèi)部類是實現(xiàn)了一個接口的匿名類。而且只能實現(xiàn)一個接口。
B. 參數(shù)式的匿名內(nèi)部類。
- class Bar{
- void doStuff(Foo f){
- }
- }
- interface Foo{
- void foo();
- }
- class Test{
- static void go(){
- Bar b = new Bar();
- b.doStuff(new Foo(){
- public void foo(){
- System.out.println("foofy");
- }
- });
- }
- }
構造內(nèi)部類對象的方法有:
1、內(nèi)部類在自己所處的外部類的靜態(tài)方法內(nèi)構建對象或在另一個類里構造對象時應用如下形式:
(1)
- OuterClass out = new OuterClass();
- OuterClass.InnerClass in = out.new InnerClass();
(2)
- OuterClass.InnerClass in=new OuterClass().new InnerClass();
其中OuterClass是外部類,InnerClass是內(nèi)部類。
2、內(nèi)部類在它所在的外部類的非靜態(tài)方法里或定義為外部類的成員變量時,則可用以下方式來構造對象:
- InnerClass in = new InnerClass();
3、如果內(nèi)部類為靜態(tài)類,則可用如下形式來構造函數(shù):
- OuterClass.InnerClass in = new OuterClass.InnerClass();
無需再利用外部類的對象來來構造內(nèi)部類對象,如果靜態(tài)內(nèi)部類需要在靜態(tài)方法或其它類中構造對象就必須用上面的方式來初始化。
原文鏈接:http://www.cnblogs.com/hqr9313/archive/2012/04/16/2452906.html
【編輯推薦】