看看下面这个java小程序:
public class Test {
public static void append(List list){
list.add("asdf");
}
public static void main(String[] args) {
List<Integer> intList = new ArrayList<Integer>();
append(intList);
System.out.println(intList.get(0));
}
}
//运行结果:asdf
可能会java的朋友们有的会认为这个程序有错误。不好意思,这个程序真的没错……
这涉及到JDK1.5的“新”特性——泛型。
我们可以看到,intList使用了泛型,其中的元素应该是Integer类型的,但是上例程序中却成功的将一个String类型存入了其中,更重要的是这个String字符串根本不能转换为Integer类型。
好吧,我们不得不承认,我们成功的“穿墙”了——绕过了泛型检查。
那么,我们是怎么做到的呢?
正如你所见,虽然我们声明了一个List<Integer>类型的链表,但是,当我们把这个链表当参数传给Test类的append方法时,我们看到append方法的形参是不带泛型的。也就是说,理论上我们可以在这个传入的链表中加入任何类型的元素。
好吧,最后我们就把一个字符串加入到了intList中去了……
是不是很神奇啊?
其实不然,我们只是简单的绕过了泛型的检查而已。我说绕过了检查,那么,是谁检查的呢?
你猜对了,就是编译器!!!
编译器干了什么?
问得好!我们要知道的是,java中的泛型基本上完全是在编译器中实现的(话怎么这么绕呢),由编译器执行类型检查和类型推断,然后生成普通的无泛型的字节码。这种实现技术我们称其为擦除(erasure)。
那么好了,我们更清晰的知道在上例中我们干了什么了——我们成功“忽悠”了编译器。(心里很爽啊,原来编译器也2啊)
那么这下好了,编译器绕过了,那么你认为接下来我们是不是可以为所欲为了呢?
呵呵,你看到了,我们已经“犯罪”了,可是JVM居然还呆呆的运行着,明明intList里只能有Integer的元素,现在可好,居然把"asdf"都打印出来了。呵呵………………
为所欲为?你真以为你是神啊?
你在打印语句中打印这个东东试试:
intList.get(0).getClass()
怎么样,傻了吧?
发生了什么事?想知道?
可是,我现在只是在说怎么绕过泛型检查,好了,老实说,我已经说完了!!
你还想知道什么呢?这跟我有什么关系?
等我下次心情好的时候再跟我说吧,或许我会说点什么的!!
呵呵…………………………………………………………………………………………………………