博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java--128陷阱
阅读量:3913 次
发布时间:2019-05-23

本文共 1914 字,大约阅读时间需要 6 分钟。

这是我们今天要讨论的话题,因为我觉得它非常的有趣。

如果你运行如下代码:

class  A{    public static void main(String[] args)     {        Integer a = 128, b = 128;        System.out.println(a == b);        Integer c = 127, d = 127;        System.out.println(c == d);    }}

你会得到如下结果:

falsetrue

我们知道,如果两个引用指向同一个对象,那么==就成立;反之,如果两个引用指向的不是同一个对象,那么==就不成立,即便两个引用的内容是一样的。因此,结果就会出现false。

这是非常有趣的地方。如果你查看Integer.java类,你会找到IntegerCache.java这个内部私有类,它为-128到127之间的所有整数对象提供缓存。

这个东西为那些数值比较小的整数提供内部缓存,当进行如此声明时:

Integer c = 127

它的内部就是这样的:

Integer var3 = Integer.valueOf(127);

其实我通过将A.class文件反编译后,代码如下图:

如果我们观察valueOf()类函数,我们可以看到:

public static Integer valueOf(int i) {        if (i >= IntegerCache.low && i <= IntegerCache.high)            return IntegerCache.cache[i + (-IntegerCache.low)];        return new Integer(i);    }

通过看源码能够知道,整数类型在-128~127之间时,会使用缓存,造成的效果就是,如果已经创建了一个相同的整数,使用valueOf创建第二次时,不会使用new关键字,而用已经缓存的对象。所以使用valueOf方法创建两次对象,若对应的数值相同,且数值在-128~127之间时,两个对象都指向同一个地址。

因此。。。

 

Integer c = 127, d = 127;

两者指向同样的对象。

这就是为什么下面这段代码的结果为true了:

System.out.println(c == d);

现在你可能会问,为什么会为-128到127之间的所有整数设置缓存?

这是因为在这个范围内的小数值整数在日常生活中的使用频率要比其它的大得多,多次使用相同的底层对象这一特性可以通过该设置进行有效的内存优化。你可以使用reflection API任意使用这个功能。

运行下面的这段代码,你就会明白它的神奇所在了。

 

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {      Class cache = Integer.class.getDeclaredClasses()[0];       Field myCache = cache.getDeclaredField("cache");      myCache.setAccessible(true);      Integer[] newCache = (Integer[]) myCache.get(cache);       newCache[132] = newCache[133];       int a = 2;      int b = a + a;      System.out.printf("%d + %d = %d", a, a, b); //    }

打印结果竟然是:

2 + 2 = 5

我们再次看一下反汇编代码:

是不是又和上面的是同一个问题呢?

但是结果为什么是 2 + 2 = 5 呢?

我们继续去看一下 Integer 源码,去深入了解 Integer 缓存机制,下面截个图:

根据源码可以发现最后修改 Integer 缓存上限时候的方法有点小瑕疵。我们看看Api给我们怎么建议的一段话:

the size of the cache may be controlled by the {@code -XX:AutoBoxCacheMax=
} option.

原来我们只需要:运行时设置 -XX:AutoBoxCacheMax=133 就OK。

 

你可能感兴趣的文章
Newbe.ObjectVisitor 0.2.10 发布,更花里胡哨
查看>>
寻找性能更优秀的动态 Getter 和 Setter 方案
查看>>
跟我一起学.NetCore之EF Core 实战入门,一看就会
查看>>
.NET架构小技巧(8)——优待异常
查看>>
一款基于.NET Core的认证授权解决方案-葫芦藤1.0开源啦
查看>>
寻找性能更优秀的不可变小字典
查看>>
项目开发中经常有一些被嫌弃的小数据,现在全丢给 FastDFS
查看>>
EntityFramework Core上下文实例池原理
查看>>
C# 8: 可变结构体中的只读实例成员
查看>>
11座城市,58个.NET最新岗位速览,内推直通面试官!
查看>>
【招聘(深圳)】华强方特文化科技集团 .NET工程师
查看>>
ASP.NETCore小技巧:使用测试用户中间件
查看>>
.NetCore HttpClient发送请求的时候为什么自动带上了一个RequestId头部?
查看>>
.NET 5 和 C#9 /F#5 一起到来, 向实现 .NET 统一迈出了一大步
查看>>
程序员过关斩将--从未停止过的系统架构设计步伐
查看>>
.NET Core 取消令牌:CancellationToken
查看>>
BCVP开发者说第一期:Destiny.Core.Flow
查看>>
行业思考 | 互联网对传统行业的降维打击
查看>>
简单聊聊C#中lock关键字
查看>>
.NET 5.0正式发布,有什么功能特性(翻译)
查看>>