Java Gossip: 內部類別(Inner class)
2007-03-15 12:19
330 查看
在類別中您還可以定義類別,稱之為內部類別(Inner class)或「巢狀類別」(Nested class)。非"static"的內部類別可以分為三種:成員內部類別(Member inner class)、區域內部類別(Local inner class)與匿名內部類別(Anonymous inner class)。
使用內部類別的好處在於可以直接存取外部類別的私用(private)成員,舉個例子來說,在視窗程式中,您可以使用內部類別來實作一個事件傾聽者類別,這個視窗傾聽者類別可以直接存取視窗元件,而不用透過參數傳遞。
另一個好處是,當某個Slave類別完全只服務於一個Master類別時,我們可以將之設定為內部類別,如此使用Master類別的人就不用知道 Slave的存在。
成員內部類別是直接宣告類別為成員,例如:
public class OuterClass {
// ....
// 內部類別
private class InnerClass {
// ....
}
}
內部類別同樣也可以使用"public"、"protected"或"private"來修飾,通常宣告為"private"的情況較多,下面這個程式簡單示範成員內部類別的使用:
OutClass.java
上面的程式假設Point類別只服務於OutClass類別,所以使用OutClass時,不必知道Point類別的存在,例如:
UseInnerClass.java
區域內部類別的使用與成員內部類別類似,區域內部類別定義於一個方法中,類別的可視範圍與生成之物件僅止於該方法之中,區域內部類別的應用一般較為少見。
內部匿名類別可以不宣告類別名稱,而使用new直接產生一個物件,該物件可以是繼承某個類別或是實作某個介面,內部匿名類別的宣告方式如下:
new [類別或介面()] {
// 實作
}
一個使用內部匿名類別的例子如下所示,您直接繼承Object類別來生成一個物件,並改寫其toString()方法:
UseInnerClass.java
執行結果:
注意如果要在內部匿名類別中使用某個方法中的變數,它必須宣告為"final",例如下面是無法通過編譯的:
....
public void someMethod() {
int x = 10;
Object obj = new Object() {
public String toString() {
return "" + x;
}
};
System.out.println(obj.toString());
}
編譯器會回報以下的錯誤:
local variable x is accessed from within inner class; needs to be declared final
您要在 x 宣告時加上final才可以通過編譯:
....
public void someMethod() {
final int x = 10;
Object obj = new Object() {
public String toString() {
return "" + x;
}
};
System.out.println(obj.toString());
}
究其原因,在於 區域變數 x 並不是真正被拿來於內部匿名類別中使用,而是在內部匿名類別中複製一份,作為field成員來使用,由於是複本,即便您在內部匿名類別中對 x 作了修改,會不會影響真正的區域變數 x,事實上您也通不過編譯器的檢查,因為編譯器要求您加上"final"關鍵字,這樣您就知道您不能在內部匿名類別中改變 x 的值。
內部類別還可以被宣告為"static",不過由於是"static",它不能存取外部類別的方法,而必須透過外部類別所生成的物件來進行呼叫,一般來說較少使用,一種情況是在main()中要使用某個內部類別時,例如:
UseInnerClass.java
由於main()方法是"static",為了要能使用Point類別,該類別也必須被宣告為"static"。
被宣告為static的內部類別,事實上也可以看作是另一種名稱空間的管理方式,例如:
public class Outer {
public static class Inner {
....
}
....
}
您可以如以下的方式來使用Inner類別:
Outer.Inner inner = new Outer.Inner();
在檔案管理方面,內部類別在編譯完成之後,所產生的檔案名稱為「外部類別名稱$內部類別名稱.class」,而內部匿名類別則在編譯完成之後產生「外部類別名稱$編號.class」,編號為1、2、3.....,看它是外部類別中的第幾個匿名類別。
使用內部類別的好處在於可以直接存取外部類別的私用(private)成員,舉個例子來說,在視窗程式中,您可以使用內部類別來實作一個事件傾聽者類別,這個視窗傾聽者類別可以直接存取視窗元件,而不用透過參數傳遞。
另一個好處是,當某個Slave類別完全只服務於一個Master類別時,我們可以將之設定為內部類別,如此使用Master類別的人就不用知道 Slave的存在。
成員內部類別是直接宣告類別為成員,例如:
public class OuterClass {
// ....
// 內部類別
private class InnerClass {
// ....
}
}
內部類別同樣也可以使用"public"、"protected"或"private"來修飾,通常宣告為"private"的情況較多,下面這個程式簡單示範成員內部類別的使用:
OutClass.java
public class OutClass { // 內部類別 private class Point { private int x, y; public Point() { x = 0; y = 0; } public void setPoint(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } private Point[] points; public OutClass(int length) { points = new Point[length]; for(int i = 0; i < points.length; i++) { points[i] = new Point(); points[i].setPoint(i*5, i*5); } } public void showPoints() { for(int i = 0; i < points.length; i++) { System.out.printf("Point[%d]: x = %d, y = %d%n", i, points[i].getX(), points[i].getY()); } } }
上面的程式假設Point類別只服務於OutClass類別,所以使用OutClass時,不必知道Point類別的存在,例如:
UseInnerClass.java
public class UseInnerClass { public static void main(String[] args) { OutClass out = new OutClass(10); out.showPoints(); } }
區域內部類別的使用與成員內部類別類似,區域內部類別定義於一個方法中,類別的可視範圍與生成之物件僅止於該方法之中,區域內部類別的應用一般較為少見。
內部匿名類別可以不宣告類別名稱,而使用new直接產生一個物件,該物件可以是繼承某個類別或是實作某個介面,內部匿名類別的宣告方式如下:
new [類別或介面()] {
// 實作
}
一個使用內部匿名類別的例子如下所示,您直接繼承Object類別來生成一個物件,並改寫其toString()方法:
UseInnerClass.java
public class UseInnerClass { public static void main(String[] args) { Object obj = new Object() { public String toString() { return "匿名類別物件"; } }; System.out.println(obj.toString()); } }
執行結果:
匿名類別物件 |
....
public void someMethod() {
int x = 10;
Object obj = new Object() {
public String toString() {
return "" + x;
}
};
System.out.println(obj.toString());
}
編譯器會回報以下的錯誤:
local variable x is accessed from within inner class; needs to be declared final
您要在 x 宣告時加上final才可以通過編譯:
....
public void someMethod() {
final int x = 10;
Object obj = new Object() {
public String toString() {
return "" + x;
}
};
System.out.println(obj.toString());
}
究其原因,在於 區域變數 x 並不是真正被拿來於內部匿名類別中使用,而是在內部匿名類別中複製一份,作為field成員來使用,由於是複本,即便您在內部匿名類別中對 x 作了修改,會不會影響真正的區域變數 x,事實上您也通不過編譯器的檢查,因為編譯器要求您加上"final"關鍵字,這樣您就知道您不能在內部匿名類別中改變 x 的值。
內部類別還可以被宣告為"static",不過由於是"static",它不能存取外部類別的方法,而必須透過外部類別所生成的物件來進行呼叫,一般來說較少使用,一種情況是在main()中要使用某個內部類別時,例如:
UseInnerClass.java
public class UseInnerClass { private static class Point { private int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } public static void main(String[] args) { Point p = new Point(10, 20); System.out.printf("x = %d, y = %d%n", p.getX(), p.getY()); } }
由於main()方法是"static",為了要能使用Point類別,該類別也必須被宣告為"static"。
被宣告為static的內部類別,事實上也可以看作是另一種名稱空間的管理方式,例如:
public class Outer {
public static class Inner {
....
}
....
}
您可以如以下的方式來使用Inner類別:
Outer.Inner inner = new Outer.Inner();
在檔案管理方面,內部類別在編譯完成之後,所產生的檔案名稱為「外部類別名稱$內部類別名稱.class」,而內部匿名類別則在編譯完成之後產生「外部類別名稱$編號.class」,編號為1、2、3.....,看它是外部類別中的第幾個匿名類別。
相关文章推荐
- Java Gossip学习笔记 (二)
- Java中的Inner Class (一)
- Java - 静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?
- Java Gossip: autoboxing、 unboxing
- 【Java】内部类(Inner Class)如何创建(new)
- java面试题之内部类不用愁,看完就理解-什么是内部类?Static Nested Class 和 Inner Class的不同。
- Thinking in Java 笔记:Inner Class
- Java: 除了Inner Class之外的两种nested Class
- Java inner Class
- 【Java面试题】11 什么是内部类?Static Nested Class 和 Inner Class的不同。
- Java Inner Class Intruduction
- Java Inner Class, Static Inner Class, Inner Interface
- Android-Java第一课 内部类 (inner Class)
- 【Java面试题】11 什么是内部类?Static Nested Class 和 Inner Class的不同。
- [2014-10-29]JAVA笔记_内部类(Inner Class)
- Java Gossip: 邏輯、位元運算
- Java的Inner Class的实例及作用分析
- java 内部类( inner class )
- Java学习--Interface, inner class, anonymous inner class, lambda实例比较
- Java中Static Nested Class 和 Inner Class的不同