原生态类型
在没有泛型之前,如果我们要维护一个价格列表:
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]
*/
当有人插入非法数据时,编译也不会报异常
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]
*/
但是执行的时候,很容易出现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
*/
原生态类型的缺点
- 在编译时期就无法发现异常;
- 需要手动做类型的转换;
使用泛型
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";//编译报错,无法通过
// prices.add(b);
for (Integer price : prices) {
System.out.println(price / 100);
}
}
}
/*output:
1
*/
什么是泛型
泛型是在Java 1.5发行版本中增加的。
声明中具有一个或者多个类型参数的类或者接口,就是泛型类或者接口。
public interface List<E> extends Collection<E>
public interface Map<K,V>
List接口就只有单个类型参数E,表示列表的元素类型。
泛型类和接口统称为泛型。
习题
- 泛型的类型参数可以为基本类型吗?
- 参数类型的字母有限制吗?
- 必须用大写声明吗?
- 可以用多个字母声明吗?
字母 | 对应的英文单词 | 含义 |
---|---|---|
E | Element | 常用在java Collection里,如:List<E>,Iterator<E>,Set<E> |
K,V | Key,Value | 代表Map的键值对 |
N | Number | 数字 |
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)
{
}
}
多个类型参数的申明
public interface ITransfer<F, T> {
T transfer(F from);
}
基于泛型接口的实现
public class TransferImpl
implements ITransfer<AService, BService> {
@Override
public BService transfer(AService a) {
}
}
泛型方法的小技巧
当没有使用泛型方法时,实例化对象:
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>();
}
}
泛型方法的特点:无需明确指定类型参数的值,不像调用泛型构造器的时候是必须指定的。
泛型只在编译时强化它们的类型信息,并在运行时擦除它们的元素类型信息。擦除就是使泛型可以与没有使用泛型的代码随意进行交互。
无限制通配符类型
无限制通配符类型: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
*/
习题
下面两种使用方式,哪个更优雅?
if (value instanceof List) {}
if (value instanceof List<?>) {}
更高级通配符特性
术语 | 实例 |
---|---|
有限制类型参数 |
<T extends Number > |
递归类型限制 |
<T extends Comparable<T> > |
有限制通配符类型 | List<? extends Number > |