概念介紹
- 內(nèi)部類
在Java中,可以將一個類定義在另一個類里面或者一個方法里面,這樣的類稱為內(nèi)部類。內(nèi)部類是一種非常有用的特性,因為它允許你把一些邏輯相關(guān)的類組織在一起,并控制位于內(nèi)部的類的可視性。
內(nèi)部類分類
廣泛意義上的內(nèi)部類一般分為以下幾種類型:
- 成員內(nèi)部類
最普通的內(nèi)部類,它定義在另一個類的內(nèi)部,如下所示
//外部類
class Out {
private int age = 12;
//內(nèi)部類
class In {
public void print() {
System.out.println(age);
}
}
}
public class NormalInnerClass {
public static void main(String[] args) {
Out.In in = new Out().new In();
in.print();
//或者采用下種方式訪問
/*
Out out = new Out();
Out.In in = out.new In();
in.print();
*/
}
}
- 局部內(nèi)部類
局部內(nèi)部類是定義在一個方法或者一個作用域里面的類,它和成員內(nèi)部類的區(qū)別在于局部內(nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)。
interface extendInnerClass{
public int setAge();
}
//外部類
class Out {
private int age = 12;
public extendInnerClass getInnerClass(){
// 局部內(nèi)部類
class innerClass implements extendInnerClass{
public int setAge(){
age++;
return age;
}
}
return new innerClass();
}
}
public class NormalInnerClass {
public static void main(String[] args) {
Out out = new Out();
System.out.println(out.getInnerClass().setAge());
}
}
注意,局部內(nèi)部類就像是方法里面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。
- 靜態(tài)內(nèi)部類
class Out3 {
private static int age = 12;
static class In {
public void print() {
System.out.println(age);
}
}
}
public class staticInnerClass {
public static void main(String[] args) {
Out3.In in = new Out3.In();
in.print();
}
}
可以看到,如果用static 將內(nèi)部內(nèi)靜態(tài)化,那么內(nèi)部類就只能訪問外部類的靜態(tài)成員變量,具有局限性
其次,因為內(nèi)部類被靜態(tài)化,因此Out.In可以當做一個整體看,可以直接new 出內(nèi)部類的對象(通過類名訪問static,生不生成外部類對象都沒關(guān)系)
- 匿名內(nèi)部類
interface anonymous{
public void getAnonymousAge();
}
class Out4 {
private static int age = 12;
public anonymous getAnonymous(){
return new anonymous(){
@Override
public void getAnonymousAge() {
System.out.println(age);
}
};
}
}
public class anonymousInnerClass {
public static void main(String[] args) {
Out4 out = new Out4();
out.getAnonymous().getAnonymousAge();
}
}
匿名內(nèi)部類是唯一一種沒有構(gòu)造器的類。正因為其沒有構(gòu)造器,所以匿名內(nèi)部類的使用范圍非常有限,大部分匿名內(nèi)部類用于接口回調(diào)。匿名內(nèi)部類在編譯的時候由系統(tǒng)自動起名為Outter$1.class。一般來說,匿名內(nèi)部類用于繼承其他類或是實現(xiàn)接口,并不需要增加額外的方法,只是對繼承方法的實現(xiàn)或是重寫。
深入理解內(nèi)部類
為什么成員內(nèi)部類可以無條件訪問外部類的成員?
編譯器會默認為成員內(nèi)部類添加了一個指向外部類對象的引用,那么這個引用是如何賦初值的呢?
雖然我們在定義的內(nèi)部類的構(gòu)造器是無參構(gòu)造器,編譯器還是會默認添加一個參數(shù),該參數(shù)的類型為指向外部類對象的一個引用,所以成員內(nèi)部類中的Outter this&0 指針便指向了外部類對象,因此可以在成員內(nèi)部類中隨意訪問外部類的成員。從這里也間接說明了成員內(nèi)部類是依賴于外部類的,如果沒有創(chuàng)建外部類的對象,則無法對Outter this&0引用進行初始化賦值,也就無法創(chuàng)建成員內(nèi)部類的對象了。為什么局部內(nèi)部類和匿名內(nèi)部類只能訪問局部final變量?
示例代碼:
public class Test {
public static void main(String[] args) {
}
public void test(final int a) {
new Thread(){
public void run() {
System.out.println(a);
};
}.start();
}
}
如果局部變量的值在編譯期間就可以確定,則直接在匿名內(nèi)部里面創(chuàng)建一個拷貝。如果局部變量的值無法在編譯期間確定,則通過構(gòu)造器傳參的方式來對拷貝進行初始化賦值。
為了解決數(shù)據(jù)不一致性問題,java編譯器就限定必須將變量a限制為final變量,不允許對變量a進行更改(對于引用類型的變量,是不允許指向新的對象),這樣數(shù)據(jù)不一致性的問題就得以解決了。
- 靜態(tài)內(nèi)部類有特殊的地方嗎?
從前面可以知道,靜態(tài)內(nèi)部類是不依賴于外部類的,也就說可以在不創(chuàng)建外部類對象的情況下創(chuàng)建內(nèi)部類的對象。另外,靜態(tài)內(nèi)部類是不持有指向外部類對象的引用的,這個讀者可以自己嘗試反編譯class文件看一下就知道了,是沒有Outter this&0引用的。
??贾R點
Static Nested Class 和 Inner Class的不同?
在方法外部定義的內(nèi)部類前面可以加上static關(guān)鍵字,從而成為Static Nested Class,它不再具有內(nèi)部類的特性,所有,從狹義上講,它不是內(nèi)部類。Static Nested Class與普通類在運行時的行為和功能上沒有什么區(qū)別,只是在編程引用時的語法上有一些差別,它可以定義成public、protected、默認的、private等多種類型,而普通類只能定義成public和默認的這兩種類型。在外面引用Static Nested Class類的名稱為“外部類名.內(nèi)部類名”。在外面不需要創(chuàng)建外部類的實例對象,就可以直接創(chuàng)建Static Nested Class,例如,假設(shè)Inner是定義在Outer類中的Static Nested Class,那么可以使用如下語句創(chuàng)建Inner類:
Outer.Inner inner = new Outer.Inner();
由于static Nested Class不依賴于外部類的實例對象,所以,static Nested Class能訪問外部類的非static成員變量。當在外部類中訪問Static Nested Class時,可以直接使用Static Nested Class的名字,而不需要加上外部類的名字了,在Static Nested Class中也可以直接引用外部類的static的成員變量,不需要加上外部類的名字。
在靜態(tài)方法中定義的內(nèi)部類也是Static Nested Class,這時候不能在類前面加static關(guān)鍵字,靜態(tài)方法中的Static Nested Class與普通方法中的內(nèi)部類的應(yīng)用方式很相似,它除了可以直接訪問外部類中的static的成員變量,還可以訪問靜態(tài)方法中的局部變量,但是,該局部變量前必須加final修飾符。內(nèi)部類可以引用它的包含類的成員嗎?有沒有什么限制?
完全可以。如果不是靜態(tài)內(nèi)部類,那沒有什么限制!
如果你把靜態(tài)嵌套類當作內(nèi)部類的一種特例,那在這種情況下不可以訪問外部類的普通成員變量,而只能訪問外部類中的靜態(tài)成員,例如,下面的代碼:
class Outer {
static int x;
static class Inner {
void test() {
syso(x);
}
}
}
參考文獻
[1]java中的內(nèi)部類總結(jié)
[2]Java中為什么要使用內(nèi)部類
[3]Java內(nèi)部類詳解