以前使用泛型方法的时候一直未注意到一个问题,原代码如下
package test;public class GenTest{
public <T> void copy(T from,T to){
}
public static <T> void staticCopy(T from,T to){
}
public <T> T get(T t){
return t;
}public static void main(String[] args) {
GenTest t = new GenTest();
t.copy(new Integer(1), "elliott");
}
}奇怪的是为什么t.copy(new Integer(1), "elliott");这行编译器没有报错
而使用类定义泛型时class GenTest<T>他才会报错
package test;public class GenTest{
public <T> void copy(T from,T to){
}
public static <T> void staticCopy(T from,T to){
}
public <T> T get(T t){
return t;
}public static void main(String[] args) {
GenTest t = new GenTest();
t.copy(new Integer(1), "elliott");
}
}奇怪的是为什么t.copy(new Integer(1), "elliott");这行编译器没有报错
而使用类定义泛型时class GenTest<T>他才会报错
class GenTest<T>是不会报错,new 对象时类型检查通不过,单独的泛型方法或者那个静态方法就会报错
不明白为什么编译器类型检查会通过
GenTest t = new GenTest();
t.copy(new Integer(1), "elliott");
实例方法copy相当于copy(Object from,Object to),所以不会报错。连警告都没。
2.GenTest.staticCopy(new Integer(1), "elliott"); 现在staticCopy是静态方法,为什么也不报错?因为你没有指定staticCopy方法的类型信息。此时staticCopy相当于staticCopy(Object from,Object to);
改为GenTest.<Integer>staticCopy(new Integer(1), "elliott");这样就报错了。3.把GenTest改为GenTest<T>,并且创建方式也改了:GenTest<Integer> t = new GenTest<Integer>();
t.copy(new Integer(1), "elliott"); 为什么还报错呢?原因是:
public <T> void copy(T from,T to){ }这里的<T>隐藏了class的<T>。
改正:
public <T> void copy(T from,T to){ } 改为 public void copy(T from,T to){ }
或者t.copy(new Integer(1), "elliott");改为 t.<Integer>copy(new Integer(1), "elliott");
为什么下面就可以工作
public static <T extends Comparable<T>> T max(T t1, T t2) {
if (t1.compareTo(t2) > 0)
return t1;
else
return t2;
}
}
max(new Integer(1), new Float(2));
这个会编译错误
t.copy(new Integer(1), "elliott"), 不报错, 因为此时泛型类型是Comparable, 反正是Integer和String的都实现的接口.
"而使用类定义泛型时class GenTest<T>他才会报错", 这要能用, 你也要定义类的时候使用泛型啊, 如
class ClassName<T> 这样才行, 楼主那压根不是泛型类.
if (t1.compareTo(t2) > 0)
return t1;
else
return t2;
}max(new Integer(1), "elliott");上面会报错
当然报错了, 你的Integer类和String类不一样, Integer实现的是Comparable<Integer>, String实现的是Comparable<String>, 不兼容.就算改成T extends Comparable<? super T>也会报错. 因为求Integer类和String类的混合体的最大值逻辑上说不通, 觉得这样很好啊.
}
public static void main(String[] args) {
max(new Integer(1), "elliott");
}
最后问一下,为什么max函数里面t1和t2的都是T类型,但是编译器为什么不进行类型检查
但是下面代码使用extends后却会检查
public static <T extends Comparable<T>> void max(T t1, T t2) {
System.out.println("caopare");
}
1、泛型类、泛型方法 编译时类型变量都是会擦除的;
2、类型变量如果没有限定类型,就会用Object替换,如果有会用第一个限定类型替换,必要时会转换成其它的限定类型;
3、所有的泛型类都有其原型;
4、编译器总会进行类型检查,Java是强类型语言;
5、Java中对象方法的调用执行采用的是动态绑定,实际的对象类型能根据隐藏参数this的类型推断出;public <T> void copy(T from,T to){
}
编译替换后是:
public void copy(Object from,Object to){
}public static <T extends Comparable<T>> void max(T t1, T t2) {
}
编译替换后是:
public static void max(Comparable t1, Comparable t2) {
}t.copy(new Integer(1), "elliott");这里编译不会出错了;
编译时编译器查看对象类型的方法列表(包括父类型中的方法),但只能找到copy(Object from,Object to)方法,因为Integer、String都是可以转换成Object的,编译器会进行转换t.copy((Object)new Integer(1), (Object)"elliott"),强制转换参数类型后符合方法签名中的参数类型的方法;max(new Integer(1), "elliott");编译出错;
这是个static方法,编译max(new Integer(1), "elliott")会静态绑定,编译器直接找类GenTest中是否有max方法,找到了有个名为max的方法,参数类型中的Comparable是个泛型类型(你声明的是个Comparable<T>,编译器会记录下T的类型是Comparable<T>类型或其子类型,尽管擦除时用的是原型Comparable替换),于是max(new Integer(1), "elliott")会进行转换:max((Comparable<Integer>)new Integer(1), (Comparable<String>)"elliott"),尽管Integer是Comparable<Integer>的子类型、String是Comparable<String>的子类型,但Comparable<Integer>和Comparable<String>是没有什么关系的,编译器就报错,类型替换失败;
但你自己强制类型转换为Comparable<T>的父类型Comparable就不会报错了,即max((Comparable)new Integer(1), (Comparable)"elliott");或去掉方法声明中的Comparable<T>中的T;