`

教你怎么绕过泛型检查

    博客分类:
  • Java
阅读更多
  看看下面这个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()

  怎么样,傻了吧?

  发生了什么事?想知道?

  可是,我现在只是在说怎么绕过泛型检查,好了,老实说,我已经说完了!!

  你还想知道什么呢?这跟我有什么关系?

  等我下次心情好的时候再跟我说吧,或许我会说点什么的!!

  呵呵…………………………………………………………………………………………………………
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics