Java泛型使用示例整理
目標
Java泛型編程是JDK1.5版本后引入的。泛型讓編程人員能夠使用類型抽象,通常用于集合里面。本文旨在整理一些泛型的用法。
用法
泛型分兩部分。一部分是泛型類和方法的定義。另一部分是泛型類和方法的使用。
定義篇
類定義時,使用泛型
在定義類的時候,我們可以使用泛型。如下代碼:
class Demo <T> {
T field;
public void setFiled(T field) {
this.field = field;
}
public T getField() {
return field;
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo<String> demo = new Demo<String>();
demo.setFiled("www.bo56.com");
System.out.println(demo.getField());
}
}
類名后面增加<T>,說明是泛型類。T可以視為類型的占位符。泛型類的代碼就可以使用這個占位符T。
無參數方法定義時,使用泛型
無論在泛型類,還是普通類中,我們都可以再方法中使用泛型。
import java.util.ArrayList;
import java.util.List;
class Demo {
public <T> List<T> newArrayList() {
return new ArrayList<T>();
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo demo = new Demo();
List<String> list = demo.newArrayList();
list.add("www.bo56.com");
list.add("bo56.com");
//list.add(1); 報錯。只能添加String
for (String str:list) {
System.out.println(str);
}
}
}
方法的返回值前面,修飾符后面增加<T>,表示為泛型方法。這樣,就可以在方法的代碼中使用T代表類型。
沒有參數的泛型方法,類型的確定,是根據等號左邊的類型推導泛型的最終類型。
有參數方法定義時,使用泛型
class Demo {
public <T> void showClass(T t) {
System.out.println(t.getClass());
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo demo = new Demo();
demo.showClass("123");
demo.showClass(123);
}
}
有參數的泛型方法,類型的確定,是根據參數類型自動推導。
方法定義時,使用通配符 ?
import java.util.ArrayList;
import java.util.List;
class Demo {
public void show(List<?> list) {
list.add(null);
//list.add(123); 編譯錯誤
for (Object object:list) {
System.out.println(object);
}
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo demo = new Demo();
List<String> listStr = new ArrayList<String>();
listStr.add("abc");
demo.show(listStr);
List<Long> listLong = new ArrayList<Long>();
listLong.add(123L);
demo.show(listLong);
}
}
1、只能往集合中add null。
2、因為集合中的類型不確定。因此,為了安全,轉換為Object。
類或者方法定義時,使用通配符 <T extends Number>
class Demo {
public <T extends Number> void showClass(T t) {
System.out.println(t.getClass());
}
}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Demo demo = new Demo();
demo.showClass(123);
demo.showClass(123f);
demo.showClass(123L);
// demo.showClass("123"); 有錯誤 參數的類型,只能是 Number類型或者其子類
}
}
<T extends Number> 表示傳入的類型必須是Number或者其子類型。
使用篇
指定固定的類型
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<Long> list = new ArrayList<Long>();
//List<Number> listN = new ArrayList<Long>(); 編譯錯誤。List<Number> 并不是 ArrayList<Long> 的父類。
}
}
如果變量聲明時,為泛型指定的類型為固定類型。如List<Long>,就是為泛型指定的類型為Long。那么后續在給變量賦值時,指定的變量也得為這個類型。如 ArrayList<Long>(),指定的也是Long。
對于泛型來說,Long是Number的子類。但是,List<Long>并不是List<Number>的子類。
使用通配符 ?
import java.util.ArrayList;
import java.util.List;
class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<?> list = new ArrayList<Fruit>();
//list.add(new Food()); 編譯錯誤
//list.add(new Fruit()); 編譯錯誤
//list.add(new Apple()); 編譯錯誤
list.add(null);
//Food food = list.get(0);
//Fruit fruit = list.get(0);
//Apple apple = list.get(0);
Object object = list.get(0);
}
}
1、只能添加null。
2、獲取的值只能賦值給Object類型。
因為通配符?表示該集合存儲的元素類型未知,可以是任何類型。往集合中加入元素需要是一個未知元素類型的子類型,正因為該集合存儲的元素類型未知,所以我們沒法向該集合中添加任何元素。唯一的例外是null,因為null是所有類型的子類型,所以盡管元素類型不知道,但是null一定是它的子類型。
使用上界通配符 <? extends Fruit>
import java.util.ArrayList;
import java.util.List;
class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<? extends Fruit> list = new ArrayList<Fruit>();
// List<? extends Fruit> listA = new ArrayList<Food>(); 編譯錯誤。不能為父類。
List<? extends Fruit> listN = new ArrayList<Apple>();
listN.add(null);
//listN.add(123); 不能add
Fruit fruit = listN.get(0);
Food food = listN.get(0);
//Apple apple = listN.get(0); 編譯錯誤。get獲取的值,只能給父類
listN.remove(0);
}
}
上界通配符,一般用于讀取的場景。
1、為泛型指定的類型只能是Fruit類型或者其子類。
2、只能為其列表添加null。
3、get方法獲取的值只能賦值給Fruit類或者其超類。
使用下界通配符 <? super Fruit>
import java.util.ArrayList;
import java.util.List;
class Food {}
class Fruit extends Food {}
class Apple extends Fruit {}
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<? super Fruit> list = new ArrayList<Fruit>();
List<? super Fruit> listA = new ArrayList<Food>();
//List<? super Fruit> listN = new ArrayList<Apple>(); 編譯錯誤,不能為子類
listA.add(new Fruit());
//listA.add(new Food()); 編譯錯誤,不能為父類。
listA.add(new Apple());
Object object = listA.get(0);
//Fruit fruit = listA.get(0);編譯錯誤。
//Food food = listA.get(0);編譯錯誤。
//Apple apple = listA.get(0); 編譯錯誤。
}
}
下界通配符,一般用于寫入的場景。
1、為泛型指定的類型必須為Fruit,或者其超類。
2、可以為其列表添加任意Fruit類型,或者其子類。
3、get方法獲取的類型,只能賦值給Object類型。
邊界通配符總結
邊界通配符總結
如果你想從一個數據類型里獲取數據,使用 ? extends 通配符
如果你想把對象寫入一個數據結構里,使用 ? super 通配符
如果你既想存,又想取,那就別用通配符。
注意
泛型類型是被所有調用共享的
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<String>l1 = new ArrayList<String>();
List<Integer>l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass()); //True
}
}
所有泛型類的實例都共享同一個運行時類,類型參數信息會在編譯時被擦除。因此考慮如下代碼,雖然ArrayList<String>和ArrayList<Integer>類型參數不同,但是他們都共享ArrayList類,所以結果會是true。
instanceof
import java.util.ArrayList;
import java.util.Collection;
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
Collection cs = new ArrayList<String>();
if (cs instanceof Collection<String>){}// compile error.如果改成instanceof Collection<?>則不會出錯。
}
}
不能對確切的泛型類型使用instanceOf操作。如下面的操作是非法的,編譯時會出錯。
泛型數組問題
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<String>[] lsa = new ArrayList<String>[10]; //compile error.
}
}
不能創建一個確切泛型類型的數組。
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main (String[] args) throws java.lang.Exception
{
List<?>[] lsa = new ArrayList<?>[10]; // ok, array of unbounded wildcard type
}
}
能創建帶通配符的泛型數組.
參考
http://qiemengdao.iteye.com/blog/1525624
http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html