泛型拾遺一下
一、為什麽想到再學習一下泛型?
最近需要寫幾個這樣的報表,怕領導看到我做一個隱藏哈,你們懂的~哈哈~
然後基本的類型返回都是一樣的格式就是生成一個json嘍,有個什麽父親節點這種,具體那個什麽節點類型的我就不說了,當然這個插件還沒有改造完成,等等有時間的時候我準備在完善一下這個插件。這個當時把大神東西拷下來的時候是有點問題,我稍微修復了一下,準備等等忙完這段時間再好好擴展一下。接下來就說我們要關註的重點泛型,因為報表的類型都基本一樣,所以返回的類型也基本相同,無謂就是多創建了幾個實體類然後在前端展示一下嘍,當然我作為這麽懶的程序員怎麽可以老是粘貼代碼尼~這是不應該的,我腦袋靈光一閃瞬間想到了泛型,用泛型方法傳入不同的類型參數,這個地方我提一下我那個跟節點是沒有父節點的,所以我返回了一個List<object>,當然想到歸想到但是我怎麽也想不起來怎麽C#泛型方法怎麽聲明了,頓時一臉的悲劇,當然查一下資料一切都不是問題嘍,但是我後來又想了一下這地方其實不需要泛型也是可以的,我後面還做了個泛型約束,真是畫蛇添足,能這麽做都是因為對其概念沒有真正理解了,無奈。我最近學習核心卷也正好看到泛型,既然如此那我就把java泛型和C#泛型對比的來學習下,當然我沒有挑動這2者矛盾的意思~廢話不多說開始搞起來~
二、泛型有哪些好處?
使用ArrayList的時候可以插入任意的數據,不管什麽類型放入ArrayList中都會被裝箱成object類型,當我們要比較一組ArrayList中的大小的時候,其中放入了一個string類型這樣就會照成System.InvalidOperationException異常,泛型的數據是統一的,類型是安全的,一組數據是int就都是int類型,另外泛型比起ArrayList減少了裝箱和拆箱操作,節省了時間,省時間的就是性能好~哇哈哈~這麽好當然使用泛型嘍~對對忘記重要的一點也就是我上面場景用的,代碼復用性增強,這樣的圖文並茂,相信大家一定會明白泛型的好處~
三、C#泛型用法
泛型類的聲明:再類名後面放一組<>括號,要是有多個類型就用,隔開,這個是類型參數,其實我們也可以這樣理解,就是說泛型類不是類而是類的模板,在使用泛型類的時候我們必須創建類型的實例。如下樣子:
MyCompare<int> a =new MyCompare<int>();
MyCompare<string> b= new MyCompare<string>();
C#裏面提供了5種泛型:類,結構,接口,委托和方法,這就使我們程序使用起來更加靈活方便。
上面這個泛型模板裏面存在的方法就是錯誤的,錯誤的原因在於沒有約束,傳入的對象就被看作object,我們怎麽樣來避免這種錯誤,當然C#是提供了這種機制的,那就是約束,只有符合約束的類型才能構造類型。
約束使用where來進行聲明,where TypeParam:constraint,constraint,..這是一個簡單聲明泛型約束的模板,我來解釋一下具體於含義TypeParam這個表示類型的參數,constraint這個表示約束列表,也就聲明類型參數可以是那種類型,下面我簡單寫了一個例子
當然約束類型也分多種,
where T:class 限制類型參數T必須是引用類型;
where T:struct 限制類型參數必須是值類型;
where T:new() 限制參數必須帶有一個無參數的構造函數
where T:接口 限制參數必須是實現了該接口的類型或者接口
說完泛型約束接下來說一下泛型的方法,泛型方法的定義如下所示,具體的我不做過多介紹,和上面泛型類基本差不多
public static bool MyWay<T, S>(T t1, S s2)
{
return t1.Equals(s2);
}
接下來說下泛型方法的調用,第一種就屬於比較常規的調用,第二種就是泛型方法的一個特點就是類型推斷,就是編譯器再調用泛型方法的時候推斷要使用的類型簡化我們的寫法。
1).static void Main(string[] args)
{
Console.WriteLine(MyClass.MyWay<int, int>(4, 4));
Console.ReadKey();
}
2).static void Main(string[] args)
{
Console.WriteLine(MyClass.MyWay(4, 4));
Console.ReadKey();
}
說到這裏我還想說一個很有意思的東西,下面這個是錯誤的,再有泛型約束的時候也不能進行運算符操作,是不是瞬間懵逼了,沒錯我也是懵逼了好一會,這確實也是C#泛型的一個嚴重限制,說到這個需要明白一下C#是如何處理基元類型的,說到基元類型又是一臉懵逼,這裏做一下解釋,編譯器直接支持的數據類型就是基元類型,基元類型就是直接映射到FCL中存在的類型,比如 int直接映射到System.Int32類型,明白了什麽是基元類型,那我們就來說一下這個struct約束泛型的方法為什麽不能比較值,假設下面的方法是成立的,接下來我調用下面的方法MyWay<byte,byte>(100,200),這個方法最後在進行類型轉化的時候就會出現錯誤,我相信說到這裏大家就應該比較明確了,那我在最後總結一下,因為在編譯的時候不能確實泛型的類型,定義為了struct就可能是所有的值類型,所以不能處理類型任何類型的數據類型算法~~
public static byte MyWay<T, S>(T t1, S s2) where T:struct where S:struct
{
return t1+s2;
}
C#泛型先簡單的介紹到這裏,下一篇我在詳細寫一下泛型委托和更高級的逆變和協變,這個我還沒很了解了。。期待與你共成長哈哈~~
四、Java泛型用法
好處就不多說了,當然和C#基本一致的,接下來我們開始搞一搞java的用法。
還是泛型類聲明 public class TestGenercDemo<T> {} 二者基本一樣
多個泛型的聲明也是在<>中加入,分割開 如 public class TestGenercDemo<T,U> {}
這裏註意一點(這個可能是比較針對於我,因為要學習java,所以我要了解其中的各種規範方便以後更好融入團隊中,形成比較好的代碼風格),在java庫中,變量E表示集合元素的類型,K和V表示鍵值對,T表示任意類型;
另外使用就沒必要說了這個就是一個new的問題嘍,再來屬性封裝讀取值,基本就是這樣;
接下來說泛型方法
public class TestGenercDemo { public static <T> T[] getMiddle(T[] t) { T[] middle=Arrays.copyOf(t,(int)t.length/2); return middle; } public static <T> T get(T t) { return t; } public static void main(String[] args) { // TODO Auto-generated method stub String[] a={"w","c","a","b"}; String[] b=getMiddle(a); String c=get("c"); int d=get(2); System.out.println(b.length); System.out.println(c); System.out.println(d); } }
以上可以觀察出基本也和C#的方法一樣,可以自動推斷類型,就是聲明的方式有所不一樣<>和方法名中間是返回類型
接下來說一下泛型變量的約束:
這個之前我們還是來說一下錯誤案例:
這個錯誤想必以及難不到大家了,這個也是因為編譯之前不知道泛型T的類型,編譯器只能默認是object類型,所以只能調用object類下面的方法
寫這些可能是在大神面班門弄斧了,,但是我堅信我有一天會成為大神哈哈
類型限定在類,接口和方法中都可以使用,需要註意一下幾點
1).不管是類或者接口都需要使用extends
2).可以使用&符號給出多個限定
public static <T extends Number&Comparable<Integer>> boolean compareValue(T t1,T t2) { return t1.equals(t2); }
3).如果限定既有接口也有類,那麽類必須只有一個,並且放在首位置
三、結束語
上面的可能說的相對比較基礎,接下來將會有下一篇泛型拾遺2,因為我堅信基礎好,框架神木的都不是問題,紮實基礎
以上如果存在什麽錯誤歡迎大神幫忙指出一下,小弟在此感謝!!另外小弟剛剛搞一個Java群438836709歡迎各種喜歡學習的人進來交流~一起暢談人生~一起開心的學習~Go!!
泛型拾遺一下