java泛型是“伪”的,所有泛型类的类型参数在编译时都会被擦除。
用生活的例子,可以理解有个容器,本来可以放任何东西的。但是现在容器上贴了个标签“水”,意思是只能放水进去,不要放其他的东西。而这个标签的检查,也只是在编译期有这个概念,会做这个检查。到了运行期这个标签就没了,本质上又只是普通容器了,可以放任何对象。所以一个String的list我们不能直接加入Integer,但是代码里通过反射等还是能轻松的加入任何其他类型的对象.------abing said
1.将所有的泛型参数用其最左边界类型替换。
2.移除所有的类型参数。
Test1
package TestCode;
public interface TestFanxing<T> {
public int compareTo(T value);
}
java -verbose
public abstract int compareTo(java.lang.Object);
Test2--bo.jiangb
interface Comparable <A> {
public int compareTo( A that);
}
class Collections {
public static <A extends Comparable<A>>A max(Collection <A> xs) {
Iterator <A> xi = xs.iterator();
A w = xi.next();
while (xi.hasNext()) {
A x = xi.next();
if (w.compareTo(x) < 0) w = x;
}
return w;
}
}
interface Comparable {
public int compareTo( Object that);
}
class Collections {
public static Comparable max(Collection xs) {
Iterator xi = xs.iterator();
Comparable w = (Comparable) xi.next();
while (xi.hasNext()) {
Comparable x = (Comparable) xi.next();
if (w.compareTo(x) < 0) w = x;
}
return w;
}
}
Test3
下面这段代码。如果这个时候执行一下Test1<String,Long> test1 = new Test1<String,Long>()会是什么样的情况,前后的T,E之间有没有什么联系。
public class Test<T,E> {
public E valueE;
public T valueT;
}
class Test1<T,E> extends Test<T,E> {
public T value1;
}
Test1<String,Long> test1 = newTest1<String,Long>();
通过反射来看一下最后生成对象中valueE和valueT的类型,都是object,符合擦除的规则。
这个时候编译器认为valueE是String类型,valueT都是Long类型(即只能赋予对应类型的值,否则就报错)。也就是编译器认为是将传给Test1类的两个模板参数也按顺序传给了基类。
===下面这种继承是不可以的,因为编译器在检查的时候不知道这个E应该用什么类型来算===
class Test2<T> extendsTest<T,E> {
public T value1;
}
===下面这种继承是允许的,这个时候编译器会认为传个Test中的两个泛型参数对应Test3<T,E,F>中的T和E(前两个)===
class Test3<T,E,F> extendsTest<T,E> {
public T value1;
}
AT LAST
泛型在一些时候可以帮我们提前发现一些问题(类型转换方面),一些时候可以帮我们简化代码没错,不过如果过度的去使用泛型,搞得到处是泛型继承,到处是泛型的泛型的时候,就有点得不偿失了。
前一段时间刚接触过一段这样的代码,深受折磨啊!找了好几个资深同学一起帮忙看,都感觉这些东西很难理解。如果代码搞成这个样子,连最基本的易理解、易维护性都木有了,谈其他神马的也就没有什么意义了(泛型仅仅是编译期的产物,和性能什么的也搭不上边)。
所以觉得还在非常需要用的时候,再去用吧。哈哈!个人观点。