http://www.cnblogs.com/lzq198754/p/5780426.html http://www.cnblogs.com/lwbqqyumidi/p/3837629.html
1.java中的泛型,为什么会出现泛型? (参数化类型,泛型一般在集合中会被经常用到)
//没有使用泛型
public class FanxingTest { public static void main(String[] args){ List tempList = new ArrayList(); tempList.add("abcde"); tempList.add(100); for(int i=0;i<tempList.size();i++){ String tempStr = (String)tempList.get(i); //此处需要强制类型转换 } } }
以上如果没有使用泛型,程序中会需要出现强制类型转换。而且不小心放入一个Integer类型的值,会出现java.lang.ClassCastException(强制类型转换错误)异常。
//使用泛型
public class FanxingTest { public static void main(String[] args){ List<String> tempList = new ArrayList<String>(); tempList.add("abcde"); //tempList.add(100); for(int i=0;i<tempList.size();i++){ String tempStr = tempList.get(i); } } }
以上使用了泛型<String>将这个List规范成只有String类型,只有String类型的值才能被放入到这个List里边,当执行tempList.add(100);时会出现一个编译错误,所以在这样可以保证在运行时不会出现ClassCastException异常。所以使用泛型可以保证程序的质量,减少程序出现运行时错误。
2.泛型只在程序编译是起作用,在程序运行时会将泛型擦除:
public class FanxingTest { public static void main(String[] args){ List<String> tempList1 = new ArrayList<String>(); //String类型 List<Integer> tempList2 = new ArrayList<Integer>(); //Integer类型 System.out.println(tempList1.getClass().getName()); System.out.println(tempList2.getClass().getName()); System.out.println(tempList1.getClass().getName() == tempList2.getClass().getName()); } }
//输出结果
java.util.ArrayList
java.util.ArrayList
true
有以上代码可以看出,List的泛型在代码运行时是没有起作用的,输出两个不同泛型的类型是一样的,都是java.util.ArrayList。所以说泛型只在代码编译的时候存在,在运行时被擦除。
通过java反射机制的原理也可以证明:
public class FanxingTest { public static void main(String[] args){ List<String> tempList = new ArrayList<String>(); tempList.add("abcde"); Class c = tempList.getClass(); //获取tempList对象的类型c try { Method method = c.getMethod("add", Object.class); //给这个类c添加一个方法 method.invoke(tempList, 100); //在tempList这个对象上调用这个方法 System.out.println(tempList); } catch (Exception e) { e.printStackTrace(); } } }
//输出结果
[abcde, 100]
以上通过反射机制实现,绕过了编译阶段也就绕过了泛型,虽然tempList是String类型的List,但是通过反射机制还是可以将integer类型的值放进去,而且没有报错,所以再一次证明泛型是在编译时有效,在运行时无效。
3.泛型不可以是基本数据类型的
因为当不加泛型的时候,默认是Object类型的,是类类型的,所以泛型不能够是基本数据类型的。
List<int> tempLiat = new ArrayList<int>(); //是会报错的,不能够这样写
4.泛型接口,泛型类和泛型方法(都可以自己定义)
//自定义泛型类和泛型方法
public class FanxingTest<T> {
private T obj;
public FanxingTest(T tempObj){
this.obj = tempObj;
}
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
public void getData(FanxingTest<Number> fff){
System.out.println(fff);
}
public static void main(String[] args){
FanxingTest<Number> temp1 = new FanxingTest<Number>(100);
Number str = temp1.getObj();
FanxingTest<Integer> temp2 = new FanxingTest<Integer>(200);
Integer num = temp2.getObj();
temp1.getData(temp1);
//temp2.getData(temp2); //会报编译时错误
}
}
以上是自定义的泛型类和泛型方法,在main方法中分别使用泛型创建了两个对象temp1和temp2,虽然Number是Integer的父类,但是当temp2.getData(temp2)时会报编译时错误。在泛型中只能使用定义好的类型。所以在泛型的理念中:在逻辑上FanxingTest<Number>不能视为FanxingTest<Integre>的父类。
5.这是通配符就应用而生(格式类似:FanxingTest<?>)
//自定义泛型类和泛型方法 public class FanxingTest<T> { private T obj; public FanxingTest(T tempObj){ this.obj = tempObj; } public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; } public void getData(FanxingTest<?> fff){ System.out.println(fff); } public static void main(String[] args){ FanxingTest<Number> temp1 = new FanxingTest<Number>(100); Number str = temp1.getObj(); FanxingTest<Integer> temp2 = new FanxingTest<Integer>(200); Integer num = temp2.getObj(); temp1.getData(temp1);
temp2.getData(temp2); } }
运用了通配符之后,temp2.getData(temp2);就不会报错了。
类型通配符一般是使用 ? 代替具体的类型实参。注意了,此处是类型实参,而不是类型形参!且Box<?>在逻辑上是Box<Integer>、Box<Number>...等所有Box<具体类型实参>的父类。由此,我们依然可以定义泛型方法,来完成此类需求。
还有通配符上限 FanxingTest<? extends Number>
还有通配符下限 FanxingTest<? super Integer>
6.注意:Java中没有所谓的泛型数组一说。