java泛型的了解
java泛型是1.5的新特性,我们先通过一个例子来简单了解一下泛型。
泛型了解:
//在java 1.5之前,集合是这样处理的。
List c1 = new ArrayList();
c1.add("abc");
c1.add(1);
String s1 = (String) c1.get(0);
String s2 = (String) c1.get(1);
//在java 1.5之后
List<String> c1 = new ArrayList<String>();
c1.add("abc");
c1.add(1);
进一步了解泛型:
泛型的一些术语介绍:
ArrayList<E> ArrayList<String>
整个ArrayList<E>称为泛型类型。中间这个<E>称为类型变量,(类型参数)
整个ArrayList<String>称为参数化的类型,String称为实际类型参数或者类型参数的实例。
ArrayList称为原始类型。
泛型的一些思考:
一:
List<String> c1 = new ArrayList<String>();
List<Integer> c2 = new ArrayList<Integer>();
System.out.println(c1.getClass() == c2.getClass());
true
既然,字节码中已经没有了类型信息的限制,那通过反射,就可以往集合中放入其它类型的实例了。看一下如下代码:
List<String> c1 = new ArrayList<String>();
try {
Method method = c1.getClass().getMethod("add", Object.class);
method.invoke(c1, 123);
Object object = c1.get(0);
System.out.println(object);
} catch (Exception e) {
e.printStackTrace();
}
123
二:
参数化类型和原始类型的兼容性:
//可以编译通过
List<String> c1 = new ArrayList();
//可以编译通过
List c2 = new ArrayList<String>();
//不可以编译通过
List<String> c3 = new ArrayList<Object>();
//不可以编译通过
List<Object> c3 = new ArrayList<String>();
泛型的通配符:
在api文档中,经常会看到这样的“<?>”这样的问号在类的后面跟着。先通过一个需求来了解问号。
定义一个方法,可以打印任意List集合中的元素。(List<Integer>,List<String>......)这样的参数化类型都可以打印。
public void print(List<?> list){
for (Object object : list) {
System.out.println(object);
}
}
public void method1(Collection<Object> c){
//可以编译通过,add的是Object
c.add("abc");
c.add(123);
//错误,前面说过,参数化类型是不考虑继承的。所以,错误
c = new ArrayList<String>();
}
public void method2(Collection<?> c){
//并没有声明具体类型就放String?错误
c.add("abc");
//把一个?(可以匹配任意类型),让它类型参数实例为String
c = new ArrayList<String>();
}
List<? extends Number> list = new ArrayList<Integer>();
//正确
List<? super Integer> list1 = new ArrayList<Number>();
//错误
List<? super Integer> list2 = new ArrayList<String>();
//正确,可以把一个类型给?
List<?> list1 = new ArrayList<Number>();
//错误,不可以把一个?给一个具体类型
List<Number> list2 = new ArrayList<?>();
自定义泛型:
java的泛型是从c++泛型借鉴过来的,但没有c++的强大,但java还是尽可能的去模仿c++的泛型。
同样,看一个需求,写一个方法,可以实现2个数的相加,但类型不同,先看看c++的实现
template<class T>
T add(T x,T y){
return (T)x+y;
}
/**
* 如何定义一个类型,返回值之前,并紧挨着返回值。
*/
public <T> T add(T x,T y){
// The operator + is undefined for the argument type(s) T, T
// 对于T来说,可能没有+这个操作。因此,在java中不能实现c++这样的功能,但仍然了解了java中泛型在方法上的使用。
// return (T)x+y;
return null;
}
泛型的类型推断:
在上面的add方法中,尝试着这样的调用。
add(1, 2);
add(1, 2.0);
add(1, "abc");
Integer add = add(1, 2);
Number add2 = add(1, 2.0);
Object add3 = add(1, "abc");
public static <T> void copy(Collection<T> c,T[] a) {
}
//错误
copy(new ArrayList<Float>(), new Integer[10]);
自定义泛型方法&自定义泛型类
1:自定义泛型方法。如上面的add方法一样。
例子:写一个方法,可以交换一个数组中的2个位置上的值。
public static <T> void swap(T[] arr,int x,int y){
T temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
//正确
swap(new String[]{"aaa","bbb"},0, 1);
swap(new Integer[]{111,222},0, 1);
//错误
swap(new int[]{1,2}, 0, 1);
//正确
ArrayList[] a1 = new ArrayList[10];
//错误:Cannot create a generic array of ArrayList<String>
ArrayList<String>[] a2 = new ArrayList<String>[10];
public static <T extends Exception> void method() throws T{
try {
} catch (Exception e) {
throw (T)e;
}
}
public class GenericStudy<T> {
}
获取类型参数实例:
由于泛型的去类型化,在编译成字节码后已经看不到这个到底是什么类型了?如何获取?
public void apply(List<String> l){
}
try {
Method method = GenericStudy.class.getMethod("apply", List.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
ParameterizedType parameterizedType = (ParameterizedType) genericParameterTypes[0];
Type type = parameterizedType.getActualTypeArguments()[0];
Type rawType = parameterizedType.getRawType();
System.out.println(rawType+":"+type);
} catch (Exception e) {
e.printStackTrace();
}
}
interface java.util.List:class java.lang.String