C# Java 內部類之間的比較
一、引言
嚴格來說,C#並沒有“內部類”這個概念,它應該叫做“嵌套類” (Nested Class)。下面先看一段Cclass Outer
{
void Print()
{
Console.WriteLine("Hello World!");
}
class Inner
{
void Show()
{
Print();
}
}
}
將這一段代碼複製到Java中:
class Outer
{
void Print()
{
System.out.println("Hello World!");
}
class Inner
{
void Show()
{
Print();
}
}
}
二、C#中的嵌套類
從上面的例子我們至少可以看出一點:在C#中,類裏面定義一個新類,和外部的類是沒有任何關係的。雖然Inner類定義在Outer中,但是不能訪問Outer中的成員,此時,Outer更加像一個命名空間。我們可以用諸如Outer.Inner i = new Outer.Inner();之類的語句來實例化一個Inner對象。
甚至可以在C#中加入一個嵌套靜態類:
class Outer
{
static class Inner
{
public static int i = 0;
public static void Increase()
{
i++;
Console.WriteLine(i);
}
}
static void Main(string[] args)
{
Outer.Inner.Increase();
}
}
因爲C#中的嵌套類邏輯如此簡單,所以一切都是“理所當然”的,書中不會提及太多。順便說一下,隨着var關鍵字的引入,C#是支持匿名類的,例如語句var A = new { a = 3 } ;創建了一個匿名類的對象,此對象裏有一個Int32成員a,被賦予初值3。
以上的特性,在Java程序中就完全不一樣了。
三、Java中的內部類(Enclosing Type)
在第一點的Java代碼段中,我們瞭解到,內部類Inner可以調用外部類的方法,這種行爲我們叫做“閉包”(Enclosure),也就是。創建內部類的對象的我是這樣理解的:在創建了內部類後,編譯器同時還創建了一個“隱藏的引用”(姑且叫它爲Outer.this)。在最開始的例子中,我們調用Inner的Print方法時,其實調用的是Outer.this.Print。因爲這樣的特性,Java中的內部類理解起來會比C#要麻煩。
我們在C#中新建一個嵌套類的對象,可以用以下語句:
Outer.Inner i = new Outer.Inner();
但是,我們不能用這種方式在Java中實例化一個內部類。其原因是,既然內部類中包含了一個外部類的引用,那麼我們在創建內部類實例的時候,就必須要指明外部類的實例的。我們用以下特殊的語法:
Outer o = new Outer();
Outer.Inner i = o.new Inner();
首先,我們定義了一個外部類的實例o,然後我們必須要用.new方式來創建內部類的實例:o.new Inner(),並且需要注意的是,不能寫成o.new Outer.Inner(),否則編譯器會報錯。
如果我們需要在內部類中返回外部類的實例,要用[外部類名].this。如上面的兩行代碼,如果我需要在Inner類中返回外部類實例o,需要寫成:
return Outer.this;
你可以在類中嵌套若干層內部類,可以在任意一層調用外部類的成員。若內部類的層次之上存在同名成員,它會返回裏內部類最近的那一層的成員。Java對內部類的限制很少,甚至可以在方法體中定義一個內部類。
四、Java中的匿名類
Java中的匿名類和C#中的匿名類不同。Java中的匿名類要以某個類爲基類進行擴展。例如以下Java代碼段:
class Main
{
class A {}
public A test(){
return new A(){
{ num = 5; }
void run(){}
int num;
int num2 = 3;
};
}
public static void main(String[] args) {}
}
class Main
{
class A {}
public A test(final int i){
return new A(){
int num = i;
};
}
public static void main(String[] args) {}
}
如果把final去掉,將會得到一個編譯錯誤。
上段代碼等效爲:
class Main
{
class A {}
public A test(final int i){
class TempClass extends A {
int num = i;
}
return new TempClass();
}
public static void main(String[] args) {}
}
五、Java中的嵌套類
有了以上基礎,理解Java中的嵌套類(nested class)就很容易了。Java的嵌套類就是C#的嵌套類。Java中定義嵌套類的方法是將內部類聲明爲static的。無論是C#還是Java,一旦一個類是一個嵌套類,它將無法訪問外部類的非靜態成員。作爲一個Java的內部類,不得包含static成員和方法,但是嵌套類是可以的。