JDK1.5版本以後出現的新特性,用於解決安全問題,是一個類型安全機制。
好處:
1,將運行時期出現問題ClassCastException 異常 轉移到了編譯時期
方便於程序員解決問題,讓運行時間問題減少,安全
2,避免了在重寫比較器時的強制轉換麻煩
泛型格式:
通過 < > 來定義要操作的引用數據類型。
泛型的限定:
? 通配符,也可以理解爲佔位符。
? extends E 可以接收 E 及其子類。 稱上限。
? super E 可以接收 E 及其父類。 稱下限。
注意:像這種 ArrayList <Person> al3 = new ArrayList <Student> ();
泛型裏兩邊不一樣是不是行的。必須是要一樣的,子父類也不行。
泛型裏的類型必須是引用類型,不能是基本數據類型,否則報錯。
例:
public void method4(ArrayList < ? extends Person > al) //此方法只能接收Person及其子類
{
Iterator < ? extends Person> it = al.iterator(); //迭代的時候也要加上泛型
while (it.hasNext())
{
System.out.println(it.next().getName());
}
}
public void method3(ArrayList< ? super Student> al) //此方法能接收Student及其父類
{
Iterator< ? super Student> it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
public < T > void method2(ArrayList< T > al) //此方法可以適用於所有類型的ArrayList集合
{
Iterator < T > it = al.iterator();
while (it.hasNext())
{
T t = it.next(); //好處是可以在此處控制
System.out.println(t);
}
}
public void method(ArrayList< ? > al) //此方法可以適用於所有ArrayList類型的集合
{
Iterator < ? > it = al.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
在使用java提供的對象時,什麼時候寫泛型呢?
通常在集合框架中很常見,只要見到 < > 就要定義泛型。
當使用集合時,將集合中要存儲的數據類型作爲參數傳遞到 < > 中即可。
其實 < > 就是用來接收類型的。
泛型類
泛型類定義的泛型,在整個類中有效,
如果被方法使用,那麼泛型類的對象明確要操作的具體類型後,所有要操作的類型就已經固定了
爲了讓方法可以操作不同類型,可以將泛型定義在方法上
特殊之處:
靜態方法不可以訪問類上定義的泛型。
如果想讓靜態方法操作不確定的應用數據類型,可以將泛型定義在靜態方法上。
例 :
class Demo < T >
{
public void show( T t)
{
System.out.println("show:"+t);
}
public < T > void print( T t)
{
System.out.println("print:"+t);
}
public static < T > void method( T t) //注意:泛型放在返回類型前面
{
System.out.println("static :"+t);
}
}
建立對象如:Demo<String> d = new Demo<String>();
泛型定義在接口上
例:
// 1,類實現泛型接口
interface Inter < T >
{
void show( T t);
}
class Inter2 implements Inter <String> //在實現該接口的時候指明類型
{
public void show(String s)
{
System.out.println("show:"+s);
}
}
// 建立對象
Inter2 i2 = new Inter2();
// 2,泛型類實現泛型接口
class InterImpl < T > implements Inter < T >
{
public void show( T t)
{
System.out.println("InterImp<>+show:"+t);
}
}
// 建立對象
InterImpl < Integer > al = new InterImpl < Integer > ();
// 輸出該集合元素
Iterator < Integer > it = al.iterator(); //迭代器也要帶上泛型
while (it.hasNext())
{
System.out.println(it.next().getName());
}
通過反射來獲取泛型的實際類型
如:Vector < Date > v1 = new Vector < Date >();
怎麼拿到Date這個實際類型呢?
把它轉換成方法的參數就可以拿到,因爲在編譯的時候會去泛型化。
注意:
public void apply( Vector < Date > v1) { }
public void apply( Vector < String > v1) { }
這兩種方法不是重載,編譯不通過,因爲它們是同一方法。因爲會去泛型化,編譯會去掉泛 型的限定
所以通過這點,我們就可以通過方法來獲取泛型實際類型。
例:
class Text{
public void apply( Vector < Date > v1) { }
//通過字節碼拿到方法
Method applyMethod = Text.class.getMethod(“apply” , Vector.class );
//通過方法返回方法的形參類型保存至數組中
Type [] types = applyMethod.getParameterTypes();
//參數化類型,因爲參數只有一個,我們取第一個元素即可。
ParameterizedType pType = (ParameterizedType)types[0];
//返回該參數的實際類型,因爲參數類型也可能是多個(如:Map泛型有兩個),所以這取第一個。
System.out.println( pType.getActualTypeArguments()[0] );
}