热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Java9中如何对IntegerCache进行修改详解

这篇文章主要给大家介绍了关于Java9中如何对IntegerCache进行修改的相关资料,文中通过示例代码介绍的非常详细,对大家学习或使用java9具有一定的参考学习价值,需要的朋友们下面随着小编来一起看看吧。

在开始本文的正文之前,我们下面来看看下面这段代码:

Java中Integer类的IntegerCache的作用

包名:java.lang

文件名:Integer.java

方法名:IntegerCache

方法的代码如下:

private static class IntegerCache { 
static final int high; 
static final Integer cache[]; 

static { 
final int low = -128; 

// high value may be configured by property 
int h = 127; 
if (integerCacheHighPropValue != null) { 
// Use Long.decode here to avoid invoking methods that 
// require Integer's autoboxing cache to be initialized 
int i = Long.decode(integerCacheHighPropValue).intValue(); 
i = Math.max(i, 127); 
// Maximum array size is Integer.MAX_VALUE 
h = Math.min(i, Integer.MAX_VALUE - -low); 
} 
high = h; 

cache = new Integer[(high - low) + 1]; 
int j = low; 
for(int k = 0; k 

我们在代码中看到,low为-128,high为127,这样的话,在Java编程中,如果要使用-128——127这个区间的对象的话,是直接使用这个Cache中的对象的。

上面是段简单的介绍,帮助大家理解下IntegerCache,下面开始本文的正文:

引言

5 年前,我在 Hungarian 上发表了一篇关于 JDK 中如何改变 IntegerCache 的文章。这种做法其实是深入进 Java 运行时,在实际并没有使用的场景。当你开发这些研究代码时,你才能更好的理解反射是如何工作的,以及 Integer 类是如何实现的。

Integer 类有一个私有的嵌套内,名为 IntegerCache ,包含了值从 -127 到 128 的 Integer 对象。

当代码需要从 int 类型封箱成 Integer 对象,而且值在这个范围内时,那么 Java 运行时会使用这个缓存,而不是创建一个新的 Integer 对象。这主要是处于性能优化的考虑,我们必须牢记在心的是很多 int 值在程序中很多时候都处于这个范围内(例如数组的下标索引)。

这样做的副作用是,很多时候,使用等号操作符来比较两个 Integer 对象时,只要值在范围内都是有效的。这在单元测试中很典型。而在运行模式下,当数值大于 128 时,代码执行会失败。

使用反射来访问 IntegerCache 类时会导致一些奇怪的副作用,注意这会影响到整个的 JVM。如果一个 Servlet 重新定义了小的 Integer 缓存值,那么所有运行在同一个 Tomcat 下的其他 Servlet 也遭遇同样问题。

在 Lukas Eder 和 Sitepoint 上面还有其他一些文章描述此问题。

现在我已经开始在玩弄 Java 9 的早期发布版本,在我脑海里我一直要做的就是对新的 Java 版本进行各种实验。在开始之前,让我们先看看在 Java 8 中的做法。

在 Lukas 的文章中,我将他的示例代码贴在此处:

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 <<&#63; > clazz = Class.forName(
  "java.lang.Integer$IntegerCache");
 Field field = clazz.getDeclaredField("cache");
 field.setAccessible(true);
 Integer[] cache = (Integer[]) field.get(clazz);

 // Rewrite the Integer cache
 for (int i = 0; i 

此代码通过反射方式访问 IntegerCache,然后使用随机值对缓存进行填充(淘气!)。

我们尝试在 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 模块的原因,这是 JDK 的组成部分,在每个 Java 程序启动时被自动的导入,不允许打开未命名的模块。这个异常是在当我们尝试设置字段可访问属性时抛出的。

我们在 Java 8 可轻松访问的对象,现在在 Java 9 中不能访问了,因为新的模块系统对此进行了保护。代码只能访问字段、方法和其他用反射能访问的信息,只有当类在相同的模块中,或者模块打开了包用于反射方式访问。这个可以通过  module-info.java 模块定义文件来实现:

module myModule {
 exports com.javax0.module.demo;
 opens com.javax0.module.demo;
}

这个模块 java.base 不用不用自行打开用于反射访问,特别是未命名模块更不需要。如果我们创建了一个模块并进行命名,那么错误信息将包含模块的名称。

我们能否在程序里打开模块呢? java.lang.reflect.Module 模块有一个 addOpens 的方法可以做到。

可行吗?

对开发者来说坏消息是:不可行。它只能在另外一个模块中打开一个模块中的包,并且包已经在该模块中通过调用这个方法打开过。这种方法只能让模块传递给另外的模块权利,前提是另外的模块已经以某种方式打开过相同的包,而不能打开没有打开过的包(译者注:很难理解,不是吗?)。

但与此同时好消息是:Java 9 不像 Java 8 那么容易被破解。最少这个漏洞被关闭了。看起来 Java 开始往专业级发展,而不仅仅是个玩具(译者注:谁说 Java 是个玩具了?)。不久的将来你可以非常严肃的将 RPG 和 COBOL 语言的项目迁移到 Java 上了。(很抱歉,我开玩笑的)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

本文翻译自:https://dzone.com/articles/hacking-the-integercache-in-java-9


推荐阅读
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文详细介绍了如何准备和安装 Eclipse 开发环境及其相关插件,包括 JDK、Tomcat、Struts 等组件的安装步骤及配置方法。 ... [详细]
  • PyCharm下载与安装指南
    本文详细介绍如何从官方渠道下载并安装PyCharm集成开发环境(IDE),涵盖Windows、macOS和Linux系统,同时提供详细的安装步骤及配置建议。 ... [详细]
  • 资源推荐 | TensorFlow官方中文教程助力英语非母语者学习
    来源:机器之心。本文详细介绍了TensorFlow官方提供的中文版教程和指南,帮助开发者更好地理解和应用这一强大的开源机器学习平台。 ... [详细]
  • Java 中 Writer flush()方法,示例 ... [详细]
  • 技术分享:从动态网站提取站点密钥的解决方案
    本文探讨了如何从动态网站中提取站点密钥,特别是针对验证码(reCAPTCHA)的处理方法。通过结合Selenium和requests库,提供了详细的代码示例和优化建议。 ... [详细]
  • 本文探讨了如何像程序员一样思考,强调了将复杂问题分解为更小模块的重要性,并讨论了如何通过妥善管理和复用已有代码来提高编程效率。 ... [详细]
  • python的交互模式怎么输出名文汉字[python常见问题]
    在命令行模式下敲命令python,就看到类似如下的一堆文本输出,然后就进入到Python交互模式,它的提示符是>>>,此时我们可以使用print() ... [详细]
  • 火星商店问题:线段树分治与持久化Trie树的应用
    本题涉及编号为1至n的火星商店,每个商店有一个永久商品价值v。操作包括每天在指定商店增加一个新商品,以及查询某段时间内某些商店中所有商品(含永久商品)与给定密码值的最大异或结果。通过线段树分治和持久化Trie树来高效解决此问题。 ... [详细]
  • Java 中的 BigDecimal pow()方法,示例 ... [详细]
  • 本文总结了汇编语言中第五至第八章的关键知识点,涵盖间接寻址、指令格式、安全编程空间、逻辑运算指令及数据重复定义等内容。通过详细解析这些内容,帮助读者更好地理解和应用汇编语言的高级特性。 ... [详细]
  • 探讨如何高效使用FastJSON进行JSON数据解析,特别是从复杂嵌套结构中提取特定字段值的方法。 ... [详细]
  • 本文介绍如何在Linux服务器之间使用SCP命令进行文件传输。SCP(Secure Copy Protocol)是一种基于SSH的安全文件传输协议,支持从远程机器复制文件到本地服务器或反之。示例包括从192.168.45.147复制tomcat目录到本地/home路径。 ... [详细]
author-avatar
饰间人爱642_370
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有