在 Java 9 里对 IntegerCache 进行修改?
来源:互联网 发布:360浏览器mac版 编辑:程序博客网 时间:2024/06/07 20:54
五年前,我在 Hungarian 上发表了一篇关于“怎样在 JDK 中修改 IntegerCahe”的文章。侵入 Java 运行时是非常有必要的,而且有显而易见的好处。当你在编写侵入代码时,你会对反射的工作机制以及 Integer 类的实现过程有一个更加深入的理解。
Integer 类有一个私有嵌套类——IntegerCache,包含 int 值从 -127 到 128 的 Integer 对象。当代码要把一个 int 数据类型封装成 Integer 对象,并且 int 值在范围 -127~128 内时,Java 运行时环境使用缓存而不是重新创建一个 Integer 对象。这是为了加快代码优化的速度,要记住:编程中的 int 数据类型在很多情况下是在规定的范围内的(类似数组的索引)。
这样做的副作用是,在很多时候,使用等号运算符来比较两个整数对象可能会工作,只要整数值在该范围内。这通常发生在单元测试期间。 在操作模式下,当某些值大于 128 时,此代码执行失败。
使用反射对 IntegerCache 做修改也可能导致奇怪的副作用,而且这会对整个 JVM 产生影响。如果一个 servlet 重新定义了小整数的缓存值,那么在同一个 JVM 上的相同 Tomcat 中运行的所有其他 servlet 都将受到影响。
现在我已经上手了 Java 9 的早期公开版本,我想到可以用新版的 Java 来做相同的侵入操作。在开始用 Java 9 侵入之前,我们先用 Java 8 做一次。import java.lang.reflect.Field;import java.util.Random;public class Entropy { public static void main(String[] args) throws Exception { // Extract the IntegerCache through reflection //获取类 Class < ? > clazz = Class.forName( "java.lang.Integer$IntegerCache"); //获取cache成员变量 Field field = clazz.getDeclaredField("cache"); field.setAccessible(true); Integer[] cache = (Integer[]) field.get(clazz); // Rewrite the Integer cache for (int i = 0; i < cache.length; i++) { cache[i] = new Integer( new Random().nextInt(cache.length)); } // Prove randomness for (int i = 0; i < 10; i++) { System.out.println((Integer) i); } }}
上面的代码通过反射获取了 IntegerCache,然后把随机数赋值给 cache 成员变量。真调皮!
我们在 Java 9 中也能执行这些代码。但是,不要高兴得太早。当人们试图在 Java 9 中进行违规操作时,后果会更严重。
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field static final java.lang.Integer[] java.lang.Integer$IntegerCache.cache accessible: module java.base does not "opens java.lang" to unnamed module @1bc6a36e
会抛出一个 Java 8 中没有的异常。说是"对象不可访问",因为 java.base 模块(每个 java 程序都会自动导入的 JDK 运行时的一部分)不会将模块打开(侵入)到未知的模块。当我们试图设置该成员变量(cache)为“可访问的”的时候,就会抛出这个异常。
在 Java 8 中轻易就能访问到的对象在 Java 9 中变得不可访问了,因为 Java 9 中模块系统会对对象进行保护。代码只有在类处于同一模块下,或为了所有模块或本模块能进行反射性访问,模块打开包时,才能访问成员变量、方法以及其他内容。这些都是在"module-info.java"模块定义文件里配置的:
module myModule { exports com.javax0.module.demo; opens com.javax0.module.demo;}
“java.base”模块不会为了编程人员开放它本身,尤其是不会为了未知的模块——也就是我们自己运行的代码。如果我们为了自己的代码创建一个模块,并且对它进行命名,然后错误信息就会包括我们模块的名字(而不是说未知的模块)。
那我们是不是可以用 Java 9 本身有的方法来达到我们的目的呢?在“java.lang.reflect.Module”模块有一个"addOpens"方法可以做到。
这样做可以吗?
这样做是不行的,对于我们这些想这样做的人来说是个坏消息。如果包已经被模块通过上面的方法打开了,那么我们只能将模块下的包打开到别的模块。这样的话,模块可以传递给其他模块,虽然 Java 9 不对外开放的内容我们还是无法访问到 ,但是通过反射模块已经可以访问到一些包了。
但是同时,对于我们来说这也是一个好消息。不像 Java 8,Java 9 的安全性比较好,不容易被攻击。至少这个小漏洞被堵住了。看起来 Java 好像开始变成专业级别的,而不再是一个小玩物了(不好意思,开个玩笑)。在不久的将来,我们可以从 RPG 和 COBOL 迁移一些重要的程序到 Java 上来。
- 在 Java 9 里对 IntegerCache 进行修改?
- 在Java 7里如何对文件进行操作
- 在Java 7里如何对文件进行操作
- 在Java 7里如何对文件进行操作
- 在Java 7里如何对文件进行操作
- 在Java 7里如何对文件进行操作
- 怎样在C#里对xml文件进行修改,新增,删除,插入操作?
- 怎样在C#里对xml文件进行修改,新增,删除,插入操作?
- 转载:怎样在C#里对xml文件进行修改,新增,删除,插入操作?
- 在C#里对xml文件进行修改,新增,删除,插入操作
- 怎样在C#里对xml文件进行修改,新增,删除,插入操作?
- Java IntegerCache 相关知识
- Scott Mitchell 的ASP.NET 2.0数据教程之63:在事务里对数据库修改进行封装
- 在SQL Server Management Studio里对表进行修改,点击保存后提示“不允许保存更改”
- IntegerCache
- IntegerCache
- java 对数组进行插入删除修改
- java 对数组进行插入删除修改
- 压缩感知测量矩阵之有限等距性质(Restricted Isometry Property, RIP)
- 使用DWR在js中调用Java类,检验用户的唯一性
- 2.本地缓存
- Android Studio 导入BSP源码
- java日期的一些处理
- 在 Java 9 里对 IntegerCache 进行修改?
- 如何分析oracle表是否被人删除或者更新过?
- 配置jdk注意事项(java.lang.outofmemory)
- 在不超过价格上限的情况下,点k个菜有多少种点法
- Qt与MySQL连接,drivers not loaded问题
- compass 配置文件config.rb中relative_assets的作用
- Linux点点滴滴
- Android文件存储详解
- JBOSS的下载安装、环境变量配置以及部署