看看下面这个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()
怎么样,傻了吧?
发生了什么事?想知道?
可是,我现在只是在说怎么绕过泛型检查,好了,老实说,我已经说完了!!
你还想知道什么呢?这跟我有什么关系?
等我下次心情好的时候再跟我说吧,或许我会说点什么的!!
呵呵…………………………………………………………………………………………………………
分享到:
相关推荐
同时,反射可以绕过访问控制,可能导致安全问题,因此在使用时应谨慎。 9. **实际应用**:Java反射广泛应用于插件系统、框架设计(如Spring框架)、测试工具(如JUnit)以及动态代理等领域。 本Java反射教程的PPT...
通过`setAccessible(true)`可以暂时绕过访问控制检查。 7. **动态代理**:Java反射API中的`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口可以实现动态代理,允许在运行时创建代理类,...
使用反射虽然提供了强大的灵活性,但也可能引入安全风险和性能开销,因为反射操作通常比常规操作慢,并且可以绕过一些安全控制。 10. **应用场景**: 反射常用于框架开发(如Spring框架),动态代理(如JDK动态...
通过`Class.newInstance()`或`Constructor.newInstance()`方法,我们可以绕过常规的构造器调用。 4. **方法的调用**:反射可以调用类的私有方法、静态方法或实例方法,通过`Method`对象的`invoke()`方法实现。 5. ...
- **安全风险**:反射可以绕过访问控制,可能引发安全问题,因此应谨慎使用。 - **异常处理**:反射操作容易抛出异常,如`ClassNotFoundException`、`IllegalAccessException`等,编写代码时需充分捕获。 - **...
Unsafe Rust用于与外部代码和硬件交互,它绕过了Rust的安全检查,因此需要谨慎使用。 标准库为Rust提供了大量的实用工具和数据结构,包括系统命令调用、目录操作和网络模块等。文档还展示了如何使用这些工具,例如...