C#當中的泛型和java中的對比


1.C#中的泛型

先寫一個Demo:

namespace generic
{
        public class Program
        {
                static void Main(string[] args)
                {
                        GenericClass<int> gInt = new GenericClass<int>(123456); 
                        Console.WriteLine(gInt.GetType());
                        Console.WriteLine(gInt.ToString());

                        GenericClass<string> gStr = new GenericClass<string>("Test");
                        Console.WriteLine(gStr.GetType());
                        Console.WriteLine(gStr.ToString());

                        Console.Read(); 
                }

        }

        //泛型類
        public class GenericClass<T>
        {
                T _t;
                public GenericClass(T t)
                {
                        _t = t;
                }
                public override string ToString()
                {
                        return _t.ToString();
                }
        }
}

 

測試輸出:

查看一下IL

C#當中GenericClass<T>是一個泛型類,他和.net中其他的類型一樣,同樣是一個確定的類型,在不指定情況下,繼承自Object類,而且可以進行派生。

與普通類型不同的是,他是一種開放類型,.Net中規定開放類型是不能被實例化的,這就確保了開放類型的泛型參數再被指定之前,不會被實例化成任何對象。

(也沒辦法,因為也不知道開放類型需要多大的內存)

 GenericClass<string> gStr = new GenericClass<string>("Test");

 GenericClass<int> gInt = new GenericClass<int>(123456);

為開放式的類型提供泛型的實例導致一個封閉類型的產生,他們的關系如下:

上圖可以了解到封閉類型和開放類型處於同一層次,而且沒有什么關系。

 

綜上:C#泛型類在編譯時,生成中間代碼IL,通用類型T只是一個占位符。在實例化類時,根據用戶指定的數據類型代替T並由即時編譯器(JIT)生成本地代碼,這個本地代碼中已經使用了實際的數據類型,等同於用實際類型寫的類,所以不同的封閉類的本地代碼是不一樣的。按照這個原理,我們可以這樣認為: 泛型類的不同的封閉類是分別不同的數據類型。 

 

2.JAVA泛型

Java泛型的定義:泛型是JDK1.5的一項新特性,它的本質是參數化類型(Parameterized Type)的應用,也就是說所操作的數據類型被指定為一個參數,在用到的時候在指定具體的類型。這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口和泛型方法。

public class Main {

        public static void main(String[] args) {
                //定義泛型類GenericClass的一個Integer版本

                GenericClass<Integer> intOb=new GenericClass<Integer>(123456);

                intOb.ToString();

                System.out.println("----------------------------------");

                //定義泛型類GenericClass的一個String版本

                GenericClass<String> strOb=new GenericClass<String>("Test");

                strOb.ToString();
        }
}

  class GenericClass<T> {
        private T _t; //定義泛型成員變量

        public GenericClass(T t) {

                this._t = t;

        }

        public void ToString() {

                  System.out.println(_t.toString());

                  }
}

結果:

 

C#則是真實的泛型,Java的泛型是偽泛型,怎么理解偽泛型?

正確理解泛型概念的首要前提是理解類型擦出(type erasure)。

Java中的泛型基本上都是在編譯器這個層次來實現的。在生成的Java字節碼中是不包含泛型中的類型信息的。

使用泛型的時候加上的類型參數,會在編譯器在編譯的時候去掉,這個過程就稱為類型擦除。

 

如在代碼中定義的GenericClass<Integer> GenericClass<String>等類型,在編譯后都會編程GenericClassJVM看到的只是GenericClass,而由泛型附加的類型信息對JVM來說是不可見的。

Java編譯器會在編譯時盡可能的發現可能出錯的地方,但是仍然無法避免在運行時刻出現類型轉換異常的情況。

 

上面代碼中執行結果中發現,兩個版本的泛型類,都是class com.company.GenericClass,

說明泛型類型StringInteger都被擦除掉了,這個就是所謂的原始類型

 

原始類型(raw type)就是擦除去了泛型信息,最后在字節碼中的類型變量的真正類型。

 

綜上:

      泛型技術在C#Java之中的使用方式看似相同,但實現上卻有着根本性的分歧,C#里面泛型無論在程序源碼中、編譯后的IL中(Intermediate Language,中間語言,這時候泛型是一個占位符)或是運行期的CLR中都是切實存在的,List<int>List<String>就是兩個不同的類型,它們在系統運行期生成,有自己的虛方法表和類型數據,這種實現稱為類型膨脹,基於這種方法實現的泛型被稱為真實泛型

       Java言中的泛型不一,它只在程序源中存在,在編譯后的字節碼文件中,就已被替換為原來的原始型(Raw Type,也稱型)了,並且在相的地方插入了型代,因此於運行期的Java言來ArrayList<int>ArrayList<String>就是同一個類。所以說泛型技術實際上是Java語言的一顆語法糖,Java語言中的泛型實現方法稱為類型擦除,基於這種方法實現的泛型被稱為偽泛型

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM