一. 泛型
(1)
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,这个类型形参将在声明变量、创建对象、调用方法时动态指定。即传入实际的类型参数(也叫传入类型实参)。传入的类型实参的类型必须是引用类型。
比如一个求数组最大值的方法,这个方法针对的数据类型可以是任何实现了 Comparable 接口的数据类型, 并且返回值类型就是传入的数据类型,这里返回类型是可变的,就可以利用泛型来实现
/**
* 获取数组元素的最大值
*/
public static <T extends Comparable> T getMaxValue(List<T> sourceList){
if(sourceList.size() <= 0){
throw new RuntimeException("数组长度为0, 无法获取最大值");
}
Iterator<T> iterator = sourceList.iterator();
T maxItem = iterator.next();
while(iterator.hasNext()){
T nextItem = iterator.next();
if(nextItem.compareTo(maxItem) > 0){
maxItem = nextItem;
}
}
return maxItem;
}
(2) <? extends T>表示该通配符所代表的类型是 T 类型的子类。
<? super T>表示该通配符所代表的类型是 T 类型的父类。
(3) 泛型类和泛型方法
(4) Java 中的泛型基本上都是在编译器这个层次来实现的。在生成的 Java 字节代码中是不包含泛 型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个过程就称为类型擦除。
运行时没有泛型,但是动态代理又是运行时的,二者结合容易产生异常
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型和动态代理
*/
public class Invocation implements InvocationHandler {
public static void main(String[] args){
Test test = new Test();
//创建代理对象
MyInterface myInterface = (MyInterface) Proxy.newProxyInstance(
test.getClass().getClassLoader(),
test.getClass().getInterfaces(),
new Invocation()
);
List<String> result = myInterface.interceptedMethod();
/*
这里行运行会报
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
*/
String item = result.get(0);
}
//拦截 Test.interceptedMethod
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
return list;
}
}
interface MyInterface{
List<String> interceptedMethod();
}
class Test implements MyInterface{
public List<String> interceptedMethod(){
List<String> list = new ArrayList<String>();
list.add("小明");
list.add("小刚");
return list;
}
}
上面的代码中
String item = result.get(0); 这一行运行报错
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
这个例子最具体地体现了泛型擦除