如果在類中再定義一個類,則將在類中再定義的那個類稱爲內部類。
一.成員內部類
1.成員內部類介紹
在一個類中使用內部類,可以在內部類中直接獲取其所在類的私有成員變量。
成員內部類的語法如下:
public class OuterClass{ // 外部類
private class lnnerClass{ // 內部類
// .......
}
}
在內部類中可以隨意使用外部類的成員方法以及成員變量。儘管這些類成員被修飾爲private。
內部類的實例一定要綁定在外部類的實例上,如果從外部類中初始化一個內部類對象,那麼內部類對象就好綁定在外部類對象上。內部類初始化方法與其他類初始化方法相同,都是使用new關鍵字。
public class OuterClass {
innerClass in = new innerClass(); // 在外部類實例化內部類對象引用
public void ouf() {
in.inf(); // 在外部類方法中調用內部類方法
}
class innerClass {
innerClass(){ // 內部類構造方法
}
public void inf() { // 內部類成員方法
}
int y = 0; //定義內部類成員變量
}
public innerClass doit() { // 外部類方法,返回值爲內部類引用
//y = 4; // 外部類不可以直接訪問內部類成員變量
in.y = 4;
return new innerClass(); // 返回內部類的引用
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
// 內部類的對象實例化操作必須在外部類或外部類的非靜態方法中實現
OuterClass.innerClass in = out.doit();
OuterClass.innerClass in2 = out.new innerClass();
// 實例化一個內部類對象
}
}
在實例化內部類對象時,不能在new操作符之前使用外部類名稱實例化內部類對象,而是應該使用外部類的對象來創建其內部類的對象。
內部類對象會依賴於外部類對象,除非已經存在一個外部類對象,否則類中不會出現內部類對象。
2.內部類向上轉型爲接口
如果將一個權限修飾符爲private的內部類向上轉型爲其父類對象,或者直接向上轉型爲一個接口,在程序中就可以完全隱藏內部類的具體實現過程。可以在外部提供一個接口,在接口中聲明一個方法。如果在實現該接口的內部類中實現該接口的方法,就可以定義多個內部類以不同的方式實現接口中的同一個方法,而在一般的類中是不能多次實現接口中同一個方法的,這種技巧經常被應用在Swing編程中,可以在一個類中做出多個不同的響應事件。
interface OutInterface{ // 定義一個接口
public void fun();
}
public class InterfaceInner {
public static void main(String[] args) {
OuterClass2 out = new OuterClass2(); // 實例化一個OuterClass22對象
// 調用doit()方法,返回一個OutInterface接口
OutInterface outinter = out.doit();
outinter.fun(); // 調用fun()方法
}
}
class OuterClass2{
// 定義一個內部類實現OutInterface接口
private class InnerClass implements OutInterface{
InnerClass(String s){ // 內部類構造方法
System.out.println(s);
}
public void fun() { // 實現接口中的fun()方法
System.out.println("訪問內部類中的fun()方法");
}
}
public OutInterface doit() { // 定義一個方法,返回值類型爲OutInterface接口
return new InnerClass("訪問內部類構造方法");
}
}
運行結果:
OuterClass2類中定義了一個被修飾權限爲private的內部類,這個內部類實現了OutInterface接口,然後修改doit()方法,使該方法返回一個OutInterface接口。由於內部類InnerClass修飾權限爲private,所以除了OuterClass2類可以訪問該內部類之外,其他類都不能訪問,而可以訪問doit()方法。由於該方法返回一個外部接口類型,這個接口可以作爲外部使用的接口。它包含一個fun()方法,在繼承此接口的內部類中實現了該方法,如果某個類繼承了外部類,由於內部的權限不可以向下轉型爲內部類InnerClass,同時也不能訪問fun()方法,但是卻可以訪問接口中的fun()方法。這樣很好地繼承該類的子類隱藏了實現細節,僅爲編寫子類的人留下一個接口和一個外部類,同時也可以調用fun()方法,但是fun()方法的具體實現過程卻被很好地隱藏了,這就是內部類最基本的用途。
非內部類不能被聲明爲private或protected訪問類型。
3.使用this關鍵字獲取內部類與外部類的引用
如果在外部類中定義的成員變量和內部類的成員變量名稱相同,可以使用this關鍵字。
public class TheSameName{
private int x;
private class Inner{
private int x = 9;
public void doit(int x) {
x++; // 調用的是形參x
this.x++; //調用內部類的變量x
TheSameName.this.x++; //調用外部類的變量x
}
}
}
在類中,如果遇到內部類與外部類的成員變量重名的情況,可以使用this關鍵字進行處理。
二.局部內部類
內部類不僅可以在類中進行定義,也可以在類的局部位置定義,如在類的方法或者任意的作用域中均可以定義內部類。
interface OutInterface2{// 定義一個接口
}
class OuterClass3{
public OutInterface2 doit(final String x){
// 在doit()方法中定義一個內部類
class InnerClass2 implements OutInterface2{
InnerClass2(String s){
s = x;
System.out.println(s);
}
}
return new InnerClass2("doit");
}
}
三.匿名內部類
class OuterClass4{
public OutInterface2 doit(){
return new OutInterface2(){// 聲明匿名內部類
private int i = 0;
public int getValue(){
return i;
}
};
}
}
在匿名內部類定義結束後,需要加分號標識,這個分號並不是代表定義內部類結束的標識,而是代表創建OutInterface2引用表達式的標識。
匿名內部類編譯以後,會產生以“外部類$序號”爲名稱的.class文件,序號以1~n排列,分別代表1~n個匿名內部類。
四.靜態內部類
在內部類前添加修飾符static,這個內部類就變爲靜態內部類了。一個靜態內部類中可以聲明static成員,但是在非靜態內部類中不可以聲明靜態成員。靜態內部類有一個最大的特點,就是不可以使用外部類的非靜態成員。
public class StaticinnerClass{
static class Inner{
// .........
}
}
五.內部類的繼承
內部類和其他普通類一樣可以被繼承,但是繼承內部類比繼承普通類複雜,需要設置專門的語法來完成。
public class OutputInnerClass extends ClassA.ClassB{
public OutputInnerClass(Class a){
a.super();
}
}
class CLassA{
class ClassB{
}
}
在某個類繼承內部類時,必須硬性給予這個類一個帶參數的構造方法,並且該構造方法的參數爲需要繼續內部類的外部類的引用,同時在構造方法體中使用a.super()語句,這樣才能爲繼承提供必要的對象引用。
若有錯誤,歡迎指正批評,歡迎評論。
每文一句:請相信,這個世界上真的有人在過着你想要的生活。也請明白,那些人大都曾隱忍過你尚未經歷的挫折。