C# Java 內部類之間的比較

C# Java 內部類之間的比較

  一、引言

 嚴格來說,C#並沒有“內部類”這個概念,它應該叫做“嵌套類” (Nested Class)。下面先看一段Cclass Outer
{
    void Print()
    {
        Console.WriteLine("Hello World!");
    }
    class Inner
    {
        void Show()
        {
            Print();
        }
    }
}


  遺憾的是,這一段代碼不能通過編譯。編譯器會產生如下錯誤:無法通過嵌套類型“Outer.Inner”來訪問外部類型“Outer”的非靜態成員。

  將這一段代碼複製到Java中:

class Outer
{
    void Print()
    {
        System.out.println("Hello World!");
    }
    class Inner
    {
        void Show()
        {
            Print();
        }
    }
}
  發現不報錯。爲什麼Java不報錯而C#報錯呢?兩種語言對待這種“類中類”,其處理方式有什麼差別?這是我接下來想探討的問題。

  二、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();
    }
}

  Outer在Main方法中的作用,和命名空間沒有多大差別。

  因爲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) {}
}

  這個代碼風格在C#中很奇怪,下面簡單講解以下。return new A() { 表示創建一個繼承於A的一個匿名類(也就是我們不知道這個類叫做什麼名字),類的成員聲明是A()後的花括號{}所包圍的部分。 { num = 5; } 表示的是這個匿名類的構造方法 (因爲匿名類沒有名字,所以只需要用花括號包圍起來)。test方法最終返回了一個向上轉型爲A類型的匿名類,這個類只能在test方法中存在,不得超出其域。
  如果想通過傳參的方式給匿名類中的成員賦值,參數必須final的。例如下面的代碼:

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成員和方法,但是嵌套類是可以的。

 
 
 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章