C#的泛型和java的偽泛型,talk is cheap,show me the code
C#泛型
下面結果,C#里面會輸出false,如果這個還不能真正的說明C#的泛型是真的泛型,那就看下面這段代碼。
List<Test> arr1 = new List<Test>(); List<String> arr2 = new List<String>(); Console.WriteLine(arr1.GetType()); Console.WriteLine(arr2.GetType()); Console.WriteLine(arr1.GetType()==arr2.GetType());
下面這段代碼,我們通過反射執行Add方法,即使代碼編譯通過,但是執行的時候會報錯。
List<String> strList = new List<string>();
strList.Add("test");
Type type = strList.GetType();
type.GetMethod("Add").Invoke(strList, new object[] { 123 }); foreach (var t in strList) { Console.WriteLine(t); }
上面這兩段代碼證明了,C#的泛型是真的泛型,因為它確實在IL方法中,給了我們一個真實存在的類。
Java泛型
java泛型會進行類型擦除,是偽泛型。因為在java生成的字節碼中,最后泛型會背Object替代。
java中,下面這些代碼都不會報錯,足以證明,偽泛型。
System.out.println("java中的假泛型"); ArrayList<Integer> arr1=new ArrayList<>(); ArrayList<String> arr2=new ArrayList<>(); System.out.println(arr1.getClass()==arr2.getClass()); System.out.println("類型擦除"); ArrayList<Integer> list = new ArrayList<Integer>(); list.add(1); //這樣調用 add 方法只能存儲整形,因為泛型類型的實例為 Integer list.getClass().getMethod("add", Object.class).invoke(list, "asd"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); }
C#的泛型是不是真的那么好
可能有同學會問,C#如果給每個泛型都搞上一個類(在中間代碼中),那DLL/EXE會不會變得非常大,從而影響性能呢,是的,我們想到了的,CLR的設計者也想到了。
1、如果為特定類型的實參調用了一個方法,以后相同類型的實參調用這個方法,CLR只會為這個方法進行組合編譯一次。比如一個程序集使用了List<DateTime> ,一個完全不同的程序集(加載到同一個AppDomain中)也是用List<Datetime>,CLR只為會為List<DateTime>編譯一次。
2、CLR還認為所有引用類型的實參都完全相同,所以代碼可以共享,因為引用類型都是在堆上了,因為堆上的東西,都是以對象指針的形式操縱。如果是值類型的呢,就需要專門為每個值類型生成本機代碼,因為值類型是位於內存棧上的,值類型的大小不固定,即使大小一樣,也沒辦法共享代碼,因為可能要用到不同的CPU的指令來進行操作