開放類型和閉合類型
在網(wǎng)站設(shè)計、網(wǎng)站制作中從網(wǎng)站色彩、結(jié)構(gòu)布局、欄目設(shè)置、關(guān)鍵詞群組等細微處著手,突出企業(yè)的產(chǎn)品/服務(wù)/品牌,幫助企業(yè)鎖定精準用戶,提高在線咨詢和轉(zhuǎn)化,使成都網(wǎng)站營銷成為有效果、有回報的無錫營銷推廣。創(chuàng)新互聯(lián)建站專業(yè)成都網(wǎng)站建設(shè)十年了,客戶滿意度97.8%,歡迎成都創(chuàng)新互聯(lián)客戶聯(lián)系。
.NET把帶有類型參數(shù)的類型看做一個新的類型,CLR將為這些類型創(chuàng)建內(nèi)部類型對象,帶有類型參數(shù)的類型可以是類,結(jié)構(gòu),接口和委托。但是,一個帶有類型參數(shù)的類型稱為開放類型,CLR不允許開放類型實例化(就好比不允許接口實例化一樣)。
當代碼中引用了泛型類型,代碼里可以指定一組泛型類型參數(shù)。如果傳入實際的數(shù)據(jù)類型,那么這個類型就成為閉合類型,CLR允許實例化閉合類型。然而,也有可能代碼引用了泛型類型,但未指定泛型類型參數(shù),這就在CLR中創(chuàng)建了一個新的開放類型,這種類型無法實例化,看一個例子。
- internal sealed class DictionaryStringKey
:Dictionary - {
- }
- static void Main(string[] args)
- {
- Object o = null;
- // Dictionary<,> 有2個類型參數(shù)的開放類型
- Type t = typeof(Dictionary<,>);
- // 創(chuàng)建實例會失敗
- o = CreateInstance(t);
- Console.WriteLine();
- // DictionaryStringKey<>有一個類型參數(shù)的開發(fā)類型
- t = typeof(DictionaryStringKey<>);
- // 創(chuàng)建該類型的實例也會失敗
- o = CreateInstance(t);
- Console.WriteLine();
- // DictionaryStringKey
是閉合類型 - t = typeof(DictionaryStringKey
); - // 創(chuàng)建成功
- o = CreateInstance(t);
- // 輸出類型名字
- Console.WriteLine("Object type=" + o.GetType());
- }
- private static Object CreateInstance(Type t)
- {
- Object o = null;
- try
- {
- //使用默認的構(gòu)造函數(shù)來創(chuàng)造該類型的實例
- o = Activator.CreateInstance(t);
- Console.Write("Created instance of {0}", t.ToString());
- }
- catch (ArgumentException e)
- {
- Console.WriteLine(e.Message);
- }
- return o;
- }
運行結(jié)果:
Activator.CreateInstance創(chuàng)建實例的時候,會提示你該類型包含泛型參數(shù)。
輸出中,可以看到類型名稱后跟著反引號(`)以及一個數(shù)字。這個數(shù)字即類型中的類型參數(shù)的數(shù)量。比如泛型Dictionary類是2,因為它需要2個類型參數(shù)來指示TKey和TValue。DictionaryStringKey類只有1個因為它只需要指明1個類型TValue。
.NET中的類型
.net中,除了實例構(gòu)造器,CLR也支持類型構(gòu)造器(也稱作靜態(tài)夠器,類夠在其或者類型初始化器)。類型構(gòu)造器可以應(yīng)用于接口(c#中不支持),引用類型(class)和值類型(struct),和實例構(gòu)造器初始化類型的實例一樣,類型構(gòu)造器用來初始化類型的一些狀態(tài),類型的構(gòu)造器如果有的話 只可能有1個,并且是無參的。可以參考之前的文章。
http://cnn237111.blog.51cto.com/2359144/576533
由于CLR保證了類型初始化器只執(zhí)行一次,并且是線程安全的,因此類型初始化器適用于用在單例模式中對單例對象的初始化。
類型中的靜態(tài)字段可以認為是類型的一部分,而類型中的非靜態(tài)字段可以認為是實例對象的一部分。當JIT編譯器把IL語言轉(zhuǎn)換成本地的CPU指令的時候,會遇到很多類型(比如自定義的class),CLR為了能正確的加載包含這些類型的程序集,它會通過程序集的元數(shù)據(jù),抽取出類型的信息,然后創(chuàng)建這些類型的數(shù)據(jù)數(shù)據(jù)結(jié)構(gòu)。這些數(shù)據(jù)結(jié)構(gòu)作為對象存放在堆中。堆中所有的對象都有2個成員,類型對象指針和同步塊索引。類型中定義的靜態(tài)字段也包含在數(shù)據(jù)結(jié)構(gòu)對象中。類的實例對象都共享類型對象中同一個靜態(tài)字段。如下圖:方框中的Manager是類型對象,靜態(tài)字段存在于類型對象中。實例對象由橢圓框表示,指向類型對象。
對于.NET泛型來說,每一個閉合類型都有自己的靜態(tài)字段。也就是說List<>和List
- static void Main(string[] args)
- {
- bool issame = typeof(List
) == typeof(List ); - Console.WriteLine(issame);
- object o = Activator.CreateInstance(typeof(List
)); - Console.WriteLine(o.GetType());
- o = Activator.CreateInstance(typeof(List
)); - Console.WriteLine(o.GetType());
- }
運行結(jié)果如下:
Java泛型中的類型擦除
經(jīng)常聽人說起Java的泛型是偽泛型,因為在編譯或運行期間,java的JIT會對進行類型擦除。即JVM無法真正識別出泛型類型,因此在真正運行前會把泛型類型轉(zhuǎn)換成原始類型。因此,所有的泛型類型,本質(zhì)上都共享同一個類型對象。比如List
- public static void main(String[] args) throws Exception {
- List
li = new ArrayList (); - List
lf = new ArrayList (); - boolean issame = li.getClass() == lf.getClass();
- System.out.println(issame);//true
- Object o = li.getClass().newInstance();
- System.out.println(o.getClass().getName());//java.util.ArrayList
- o = lf.getClass().newInstance();
- System.out.println(o.getClass().getName());//java.util.ArrayList
- }
也正是由于代碼擦除,使得泛型類型本質(zhì)上都是共享同一個類型對象,因此類型的靜態(tài)字段也是共享的。例如下面代碼:
- public class AtestClass
{ - public static int i=0;
- public AtestClass()
- {
- i++;
- }
- }
- ------------------
- public static void main(String[] args) throws Exception {
- AtestClass
ai=new AtestClass (); - AtestClass
af=new AtestClass (); - System.out.println(AtestClass.i);
- }
最終運行的結(jié)果是2.
參考文檔:Microsoft.Press.CLR.via.Csharp.4th.Edition.Oct.2012.
https://en.wikipedia.org/wiki/Generics_in_Java.