[java核心篇02]__內部類
-
前言
其實我們在前面已經初步接觸到內部類了,但是我們去對它的作用並不勝了解.只是簡單的知道了類的定義也是可以巢狀的,定義在一個類裡面的類就是內部類.
class out{ private String name; private int age; class in{ private String sex; } public String getName(){ return this.name; } }
但是關於內部類有什麼作用,有什麼分類都不是很瞭解,通過這篇文章來對java內部類的學習進行加深.
-
內部類的特點
1、內部類可以用多個例項,每個例項都有自己的狀態資訊,並且與其他外圍物件的資訊相互獨立。
2、在單個外圍類中,可以讓多個內部類以不同的方式實現同一個介面,或者繼承同一個類。
3、建立內部類物件的時刻並不依賴於外圍類物件的建立。
4、內部類並沒有令人迷惑的“is-a”關係,他就是一個獨立的實體。
5、內部類提供了更好的封裝,除了該外圍類,其他類都不能訪問。
6、內部類可以訪問包括私有成員在內的外部類的所有成員。
- 內部類的作用
書上的描述並不詳細,於是google了下相關的文章,感覺還是說法不一, 具體的作用有很多,於是大致總結兩點:-
內部類並不象外部類一樣,它可以使用provate,proteced,這意味著它可以更好的封裝,更好的隱藏起來,在我們需要隱藏某些方法的實現細節時,可以使用到內部類.而外部類則不行.
-
另外一個作用就是能夠更好的解決java多繼承的問題,我們知道,在java語言中秉性的是單繼承,而內部類與外部類的繼承關係是互不干擾的,我們在前面知道了,java類可以通過介面的多繼承解決多繼承的問題,但那並沒有徹底解決這個問題,而通過內部類則可以徹底解決這個問題,我們可以通過內部類實現類的多繼承(可以定義多個內部類繼承多個抽象類或具體類)
-
-
內部類的分類
- 靜態內部類與非靜態內部類
靜態內部類與非靜態內部類
- 靜態內部類可以有靜態成員變數,而非靜態內部類則不能有靜態成員變數。
- 靜態內部類可以訪問外部類的靜態變數,但不可訪問外部類的非靜態變數;
- 非靜態內部類的非靜態成員方法可以訪問外部類的非靜態變數,也可以訪問靜態變數。
- 靜態內部類的建立不依賴於外部類,而非靜態內部類必須依賴於外部類的建立而建立。
- 靜態內部類與非靜態內部類
我們通過一個例子看看:
public class sty_internalClass { public static void main(String[] args) { // 建立內部類例項化物件的第一種方式.. textclass text = new textclass(); // 例項化外部類物件 textclass.internaltextclass internaltextclass = text.new internaltextclass();// 例項化內部類的物件要通過外部類物件來實現. // 建立內部類的例項化物件的第二種方式 textclass.internaltextclass internaltextclass1 = new textclass().new internaltextclass(); // 建立靜態內部類例項化物件 textclass.astaticinclass astaticinclass = new textclass.astaticinclass(); // 靜態內部類的例項化不需要依賴外部類. } } class textclass{ private String name; static private int age; public class internaltextclass{// 內部類 String sex="男"; internaltextclass(){ // 構造方法 name = "小舍"; age = 23; } void input(){ System.out.println("這是內部類的一個方法"); System.out.println(age); } } public static class astaticinclass{ void funtion(){ System.out.println(age); } } public internaltextclass getinternaltextclass(){ return new internaltextclass(); } void ainput(){// 外部類的一個方法,呼叫內部類的屬性和方法. internaltextclass internaltextclass = new internaltextclass(); internaltextclass.sex = "男"; } }
我們可以觀察出:非靜態內部類的例項化必須依賴外部類(需要通過一個外部類的例項化物件建立物件)
而靜態內部類是不依賴外部類的(可以直接建立例項化物件)
-
非靜態內部類:
- 成員內部類
- 方法(區域性)內部類
- 匿名內部類
-
成員內部類
就其文字含義而言,它就是作為一個類的成員存在的內部類.我們可以將它看做一個類的一個成員,只不過這個成員的型別是一個類而已.
class textclass{ private String name; static private int age; public class internaltextclass{// 內部類 String sex="男"; internaltextclass(){ // 構造方法 name = "小舍"; age = 23; } void input(){ System.out.println("這是內部類的一個方法"); ainput();// 可以沒有任何限制的呼叫外部類的方法. } } void ainput(){// 外部類的一個方法,呼叫內部類的屬性和方法. internaltextclass internaltextclass = new internaltextclass(); internaltextclass.sex = "男"; } }
我們甚至可以通過定義get方法來獲得一個成員內部類的物件.
public internaltextclass getinternaltextclass(){ return new internaltextclass(); }
我們可以觀察到:
- 成員內部類的定義是更成員變數並列的,所以可以看成是外部類的一個成員.
- 成員內部類的好處就是可以沒有任何限制的訪問外部類的屬性和方法.不管是靜態還是非靜態.
- 用內部類定義在外部類中不可訪問的屬性。這樣就在外部類中實現了比外部類的private還要小的訪問許可權,更好的封裝隱藏性。
(成員內部類不能有靜態成員變數和方法,這是因為成員內部類不能被定義為靜態的,定義為靜態就成了靜態內部類了,而之所以靜態內部類不叫靜態成員內部類,這應該是因為靜態內部類物件的建立不依賴於外部類,所以嚴格來說算不上是外部類的一個成員.)
-
方法(區域性)內部類
很多文章都喜歡將它稱為區域性內部類,但是我覺得這樣並不貼切,很模糊概念.其實區域性內部類就是定義在一個方法體中的內部類.它與區域性變數類似,其作用範圍也只有方法體大小,其訪問許可權也只有方法體大小,這裡我們就可以察覺到,那麼區域性內部類真的是太適合封裝了,其隱蔽性更加高了.
我們放大上面例子中的ainput方法(外部類的普通方法),在裡面加入一個區域性內部類:
void ainput(){// 外部類的一個方法,呼叫內部類的屬性和方法. final String[] a = new String[0]; internaltextclass internaltextclass = new internaltextclass(); // 通過例項化內部類來呼叫內部類的成員變數. internaltextclass.sex = "男"; // 定義區域性內部類 class Localinclass{ void Local(){ a[0] = "外部方法體中的變數"; System.out.println("區域性內部類中的方法"); System.out.println(a[0]); } } //在方法體中呼叫區域性內部類. Localinclass localinclass = new Localinclass(); localinclass.Local(); }
我們可以觀察到,在方法體中的內部類,只能從上往下執行(呼叫只能再內部類的下面,否則無法識別到,這應該是是因為java執行的機制,在方法體中是從上到下的.)
另外,在區域性內部類中,我們只能訪問到方法體中的final型變數.
-
匿名內部類
匿名內部類比較特殊,它的建立不需要類名(當然也不需要class關鍵字),但其必須繼承一個抽象類或是一個介面(只能是一個).
匿名內部類的定義是這樣的:
new 父類構造器(引數){// new一個父類的引用 類體部分 }
new 介面(){ 類體部分 }
匿名內部類實際完成的工作其實就是實現抽象類或介面中的方法.然後作為一個例項的物件被建立.
我們來看一個例子.
package java02.day_4_14; /** * @outhor xiaoshe * @date 2019/4/15- @time 1:55 * 匿名內部類 */ public class sty_anonymous { public void outman(man m){ System.out.println(m.toout()); } public static void main(String[] args) { sty_anonymous styAnonymous = new sty_anonymous(); // 匿名內部類的使用 styAnonymous.outman(new man() { @Override String sex() { return "男"; } @Override String name() { return "男人"; } @Override String toout() { return(this.name()+"\n"+this.sex()); } }); } } // 定義一個抽象類 abstract class man{ private String name; private String sex; abstract String sex(); // 定義一個抽象方法 abstract String name(); // 定義一個抽象方法 abstract String toout(); }
我們可以看出,匿名內部類在這裡的功能是實現抽象類中的抽象方法,應為抽象類是不能直接例項化的,所以這裡通過了匿名內部類繼承了抽象類man,而這裡的 new man{...}
就是整個匿名內部類,它在這裡不是作為方法 outman(man m)
中的man類例項物件 m
二存在的(因為抽象類不能直接例項化物件), 而是作為一個繼承了抽象類man的匿名內部類(即 new man{...}
)的例項化物件而存在的.同時抽象類被繼承後其抽象方法必須全部實現.
我們將整個匿名內部類收起來:
同時我們應該注意到,匿名內部類的使用範圍是十分有限的,一個匿名內部類只能被使用一次(只在一個方法中當做一個例項化物件來使用)
ps:發現昨天核心以的關於抽象類和介面的知識點有很大差錯,這次記住教訓,學東西不能圖快,切勿沒完全整明白就跳過.明天重新總結,
檢討之
更新時間:
2019-4-15
2:30