本來只轉載了個鏈接,和一個簡單的使用程序,但昨天不小心看到有人批判jdk1.5,先說java要強制轉型不好的問題沒解決,
容器不能放基類型不好,接著說泛型沒用。而恰恰Jdk1.5中解決了這些問題,所以感嘆之余,把這篇文章改一下,詳細的說說泛型。
一,Java中的泛型:
在Java中能使用到泛型的多是容器類,如各種list map set,因為Java是單根繼承,所以容器里邊可以放的
內容是任何Object,所以從意義上講原本的設計才是泛型。但用過Java的人是否感覺每次轉型很麻煩呢?
而且會有些錯誤,比如一個容器內放入了異質對象,強制轉型的時候會出現cast異常。而這中錯誤在編譯器是
無從發現的。所以jdk1.5中提供了泛型,這個泛型其實是向c++靠攏了.好,我們先看幾個實例再細說原理。
二,泛型的用法:(多個實例)
1
實例A
2
ArrayList < String > strList = new ArrayList < String > ();
3
strList.add( " 1 " );
4
strList.add( " 2 " );
5
strList.add( " 3 " );
6
// 關鍵點(1) 注意下邊這行,沒有強制轉型
7
String str = strList.get( 1 );
8
// 關鍵點(2)然後我們加入,這個時候你會發現編譯器報錯,錯誤在編譯器被發現,錯誤當然是發現的越早越好
9
strList.add( new Object());
1
實例B
2
ArrayList < Integer > iList = new ArrayList < Integer > ();
3
// 關鍵點(3) 注意直接把整數放入了集合中,而沒有用Integer包裹
4
iList.add( 1 );
5
iList.add( 2 );
6
iList.add( 3 );
7
// 關鍵點(4)同樣直接取出就是int
8
int num = iList.get( 1 );
1
實例C
2
// 關鍵點(5)展示一下key-value的時候要怎么寫,同時key和value也可以是基本類型了。
3
HashMap < Integer,Integer > map = new HashMap < Integer,Integer > ();
4
map.put( 1 , 11 );
5
map.put( 2 , 22 );
6
map.put( 3 , 33 );
7
int inum = map.get( 1 );
8
三,看完了實例了,詳細來說說為什么吧
首先jdk1.5中的泛型,第一個解決的問題,就是Java中很多不必要的強制轉型了,具體的實現,我們以ArrayList
為例,下邊是ArrayList中的片斷代碼:
1
ArrayList類的定義,這里加入了<E>
2
public class ArrayList<E> extends AbstractList<E>
3
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
4
5
//get方法,返回不再是Object 而是E
6
public E get(int index)
{
7
RangeCheck(index);
8
return elementData[index];
9
}
10
//add方法,參數不再是Object 而是E
11
public boolean add(E o)
{
12
ensureCapacity(size + 1); // Increments modCount!!
13
elementData[size++] = o;
14
return true;
15
}
16
四,Boxing 和UnBoxing
看到上邊的關鍵點(3)和(4)是否感覺驚奇呢,因為Java中煩人的除了強制轉型,另一個就是基礎類型了
放入容器的時候要包裝,取出了還要轉回。Jdk1.5中解決了這個問題.如上邊的使用方法
五,泛型的生命周期(使用注意事項)
如果我們試著把ArrayList<String> list的內容序列化,然後再讀取出來,在使用的過程中會發現出錯,
為什么呢?用Stream讀取一下回來的數據,你會發現<String>不見了,list變成了普通的ArrayList,而不是
參數化型別的ArrayList了,為什么會這樣呢 ?見下邊的比較
六,C++的泛型和Java的泛型
在泛型的實現上,C++和Java有著很大的不同,
Java是擦拭法實現的
C++是膨脹法實現的
因為Java原本實現就是泛型的,現在加入型別,其實是"窄化",所以采用擦拭法,在實現上,其實是封裝了原本的
ArrayList,這樣的話,對于下邊這些情況,Java的實現類只有一個。
1
ArrayList<Integer>
.; public class ArrayList
2
ArrayList<String>
..; --同上--
3
ArrayList<Double>
..; --同上--
4
而C++采用的是膨脹法,對于上邊的三種情況實際是每一種型別都對應一個實現,實現類有多個
5
list<int> li; class list; //int 版本
6
list<string> ls; class list; //string 版本
7
list<double> ld; class list; //double 版本
這就造成了,在序列化后,Java不能分清楚原來的ArrayList是
ArrayList<Integer>還是ArrayList
七,題外話,在很多東西的實現上C++和Java有很多不同
例如運算符的問題i=i++問題,詳細看這里
例如在C++中能很好實現的double-checked locking單態模式,在Java中幾乎很難實現 詳細看這里
還有就是上邊提到的泛型實現上。
八,Jdk 1.5加入了不少新東西,有些能很大的提高開發質量,例如Jdk1.4 ,Jdk.15中StringBuffer的不同
因為從1。4轉入1。5不久,所以慢慢會發一些在1。5的使用過程中發現的東西。
最后,我們還可以自己寫類似ArrayList這樣的泛型類,至于如何自定義泛型類,泛型方法請參見候捷先生的文章