原生態(tài)類型
在沒有泛型之前,如果我們要維護(hù)一個(gè)價(jià)格列表:
public class Main {
public static void main(String[] args) throws Exception {
List prices = new ArrayList();
Integer a = 100;
prices.add(a);
System.out.println(prices);
}
}
/*output:
[100]
*/
當(dāng)有人插入非法數(shù)據(jù)時(shí),編譯也不會報(bào)異常
public class Main {
public static void main(String[] args) throws Exception {
List prices = new ArrayList();
Integer a = 100;
prices.add(a);
String b = "test";
prices.add(b);
System.out.println(prices);
}
}
/*output:
[100, test]
*/
但是執(zhí)行的時(shí)候,很容易出現(xiàn)bug:
public class Main {
public static void main(String[] args) throws Exception {
List prices = new ArrayList();
Integer a = 100;
prices.add(a);
String b = "test";
prices.add(b);
for (Object price : prices) {
Integer tmp = (Integer)price;
System.out.println(tmp / 100);
}
}
}
/*output:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at com.dpriest.tool.automan.Main.main(Main.java:17)
1
*/
原生態(tài)類型的缺點(diǎn)
- 在編譯時(shí)期就無法發(fā)現(xiàn)異常;
- 需要手動做類型的轉(zhuǎn)換;
使用泛型
public class Main {
public static void main(String[] args) throws Exception {
List<Integer> prices = new ArrayList<Integer>();
Integer a = 100;
prices.add(a);
// String b = "test";//編譯報(bào)錯(cuò),無法通過
// prices.add(b);
for (Integer price : prices) {
System.out.println(price / 100);
}
}
}
/*output:
1
*/
什么是泛型
泛型是在Java 1.5發(fā)行版本中增加的。
聲明中具有一個(gè)或者多個(gè)類型參數(shù)的類或者接口,就是泛型類或者接口。
public interface List<E> extends Collection<E>
public interface Map<K,V>
List接口就只有單個(gè)類型參數(shù)E,表示列表的元素類型。
泛型類和接口統(tǒng)稱為泛型。
習(xí)題
- 泛型的類型參數(shù)可以為基本類型嗎?
- 參數(shù)類型的字母有限制嗎?
- 必須用大寫聲明嗎?
- 可以用多個(gè)字母聲明嗎?
字母 | 對應(yīng)的英文單詞 | 含義 |
---|---|---|
E | Element | 常用在java Collection里,如:List<E>,Iterator<E>,Set<E> |
K,V | Key,Value | 代表Map的鍵值對 |
N | Number | 數(shù)字 |
T | Type | 類型,如String,Integer等等 |
聲明泛型
泛型類
public class CacheData<T> {
private T data;
private boolean markedValue;
public CacheData() {
}
public CacheData(T data, boolean markedValue) {
this.data = data;
this.markedValue = markedValue;
}
public T getData() {
return data;
}
public boolean isMarkedValue() {
return markedValue;
}
}
泛型方法
public class TransferService {
public <T> T transfer(T toTransfer)
{
}
}
多個(gè)類型參數(shù)的申明
public interface ITransfer<F, T> {
T transfer(F from);
}
基于泛型接口的實(shí)現(xiàn)
public class TransferImpl
implements ITransfer<AService, BService> {
@Override
public BService transfer(AService a) {
}
}
泛型方法的小技巧
當(dāng)沒有使用泛型方法時(shí),實(shí)例化對象:
List<Integer> prices = new ArrayList<Integer>();
List<String> strings = new ArrayList<String>();
使用泛型方法
public class Main {
public static void main(String[] args) throws Exception {
List<Integer> prices = newArrayList();
Integer a = 100;
prices.add(a);
List<String> strings = newArrayList();
strings.add("String");
}
public static <E> List<E> newArrayList() {
return new ArrayList<E>();
}
}
泛型方法的特點(diǎn):無需明確指定類型參數(shù)的值,不像調(diào)用泛型構(gòu)造器的時(shí)候是必須指定的。
泛型只在編譯時(shí)強(qiáng)化它們的類型信息,并在運(yùn)行時(shí)擦除它們的元素類型信息。擦除就是使泛型可以與沒有使用泛型的代碼隨意進(jìn)行交互。
無限制通配符類型
無限制通配符類型:List<?>
public class Main {
public static void main(String[] args) throws Exception {
List<Integer> prices = new ArrayList<Integer>();
Integer a = 100;
prices.add(a);
List<String> strings = new ArrayList<String>();
strings.add("String");
printAnyList(prices);
printAnyList(strings);
}
private static void printAnyList(List<?> list) {
for (Object o : list) {
System.out.println(o);
}
}
}
/*output:
100
String
*/
習(xí)題
下面兩種使用方式,哪個(gè)更優(yōu)雅?
if (value instanceof List) {}
if (value instanceof List<?>) {}
更高級通配符特性
術(shù)語 | 實(shí)例 |
---|---|
有限制類型參數(shù) |
<T extends Number > |
遞歸類型限制 |
<T extends Comparable<T> > |
有限制通配符類型 | List<? extends Number > |