java 判断true false_面试题之-Java中判断200==200为false但127==127为true的疑问

Java中判断200==200为false但127==127为true的疑问

1. 问题的引出

1.1 200==200为false吗?

代码:package com.niewj.nio;

/**

* Created by niewj on 2020/9/20 11:24

*/

public class Test {

public static void main(String[] args) {

Integer i1 = 127;

Integer i2 = 127;

System.out.println("包装类 127 == 127: "+ (i1 == i2));

Integer i3 = 200;

Integer i4 = 200;

System.out.println("包装类 127 == 127: "+ (i3 == i4));

int i5 = 200;

int i6 = 200;

System.out.println("非包装int型 200 == 200: " + (i5 == i6));

}

}

控制台输出:包装类 127 == 127: true

包装类 127 == 127: false

非包装int型 200 == 200: true

看现象得结论:

1). 原生类型的200==200为true

2). 包装类Integer的200==200为false

3). 包装类Integer的127==127为true

看结论得疑惑? why??

对象类型的==比较的不是 对象的内存地址吗? 怎么这两个对象难道是一个?? 下来我们找找原因:

1.2 为什么包装类127==127为true翻开随身携带的记事本, 写着许多事, 都是关于你....你讨厌被冷漠....习惯被守候...

跑题了, 我们不唱歌!

翻开jdk的源码, Integer:829行:public static Integer valueOf(int i) {

if (i >= IntegerCache.low && i <= IntegerCache.high)

return IntegerCache.cache[i + (-IntegerCache.low)];

return new Integer(i);

}

看代码能开出些许动过刀的嫌疑, 没错, 方法的文档注释里也说了:

1). -128到127的值被缓存此方法将始终缓存范围为-128到127(包括在内)的值,并可能缓存此范围之外的其他值。

没错了, 这就是问题的原因, 辣么, 咋个实的现?

2. 问题的原因探究

Integer类内部有个static的内部类IntegerCache, 就是实现的原因:

2.1 IntegerCache的实现:private static class IntegerCache {

static final int low = -128;

static final int high;

static final Integer cache[];

static {

// high value may be configured by property

int h = 127;

String integerCacheHighPropValue =

sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");

if (integerCacheHighPropValue != null) {

try {

int i = parseInt(integerCacheHighPropValue);

i = Math.max(i, 127);

// Maximum array size is Integer.MAX_VALUE

h = Math.min(i, Integer.MAX_VALUE - (-low) -1);

} catch( NumberFormatException nfe) {

// If the property cannot be parsed into an int, ignore it.

}

}

high = h;

cache = new Integer[(high - low) + 1];

int j = low;

for(int k = 0; k < cache.length; k++)

cache[k] = new Integer(j++);

// range [-128, 127] must be interned (JLS7 5.1.7)

assert IntegerCache.high >= 127;

}

private IntegerCache() {}

}

类的文档注释:Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS. The cache is initialized on first usage. The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option. During VM initialization, java.lang.Integer.IntegerCache.high property may be set and saved in the private system properties in the sun.misc.VM class.

机器人翻译:缓存以支持JLS要求的-128和127(包括)之间值自动装箱的对象标识语义。缓存在第一次使用时初始化。缓存的大小可以由-XX:AutoBoxCacheMax=选项控制。在VM初始化期间,java.lang.Integer.IntegerCache。高属性可以设置和保存在私人系统的阳光属性。VM类。

2.2 IntegerCache类实现简析:

1). IntegerCache类特点:static class : 只随着类的加载, 初始化一次, 跟后续的不管多少个Integer的实例无关;

static Integer cache[] : 所有Integer实例都可以共享的 cache;

static int low=-128: 最小值为 -128;

static int high; 最大值(static里有逻辑, 默认是127)

static{}块中初始化逻辑

2). 着重分析下static{}块中初始化逻辑

sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high")

代码中读取了这个属性, 然后用它跟127比, 取大的, 作为最大缓存值;

关于这个属性的意义和操作空间, 我们在最后一部分详述:问题的逆转?! 部分

现在只要知道, 默认的话, 就是:初始化了一个 static的Integer数组, 容量是256个, 存放的内容就是-128到127之间的值

我们在声明和初始化一个Integer变量的时候, 如果值的区间在 -128到127之间, 就会从这个cache数组中取;

由于这个cache数组是静态的, 所以所有的Integer的实例可以共享

所以, 包装类型的Integer 127==127 实际上都是这个cache中的第一次初始化的127的Integer对象, 必然是同一个, 就true了;

但是200就不一样了, cache的区间只有 -128到127, 200的并没有缓存, 所以会每次初始化新的Integer对象实例

3). Integer的-128到127之间的值被缓存, 非此区间的每次都是新实例对象;

3. 问题的扩展:Byte/Short/Long/Character

原因已经找到了, 我们该结束了? 不不不, 这可是一道面试题, 你不发挥发挥? 你不发挥可能就被挥发了....危....

Integer有缓存了, 那么其他的整数类型呢?

Byte/Short/Character/Long 会不会也是共犯?

我们揪出源码审问一下:

3.1 Byte的缓存-ByteCache

Byte类还没打就招了:private static class ByteCache {

private ByteCache(){}

static final Byte cache[] = new Byte[-(-128) + 127 + 1];

static {

for(int i = 0; i < cache.length; i++)

cache[i] = new Byte((byte)(i - 128));

}

}

由于Byte本身体弱能力有限, 看到刑拘就招认了; 我本身就只占一个字节, 也没什么花花肠子, 我坦白吧: 我甚至都不用什么属性配置类, 我的实现也很简单粗暴, 够用就行!

1). ByteChache实现了Byte中的-128到127的缓存

3.2 Short的缓存-ShortCache

Short占2个字节, 它的实现也简单粗暴, 够用就行, 不耍花花绕:private static class ShortCache {

private ShortCache(){}

static final Short cache[] = new Short[-(-128) + 127 + 1];

static {

for(int i = 0; i < cache.length; i++)

cache[i] = new Short((short)(i - 128));

}

}

1). ShortCache实现了Short中的-128到127的缓存

3.3 Long的缓存-LongCache:

Long可是占8个字节的, 壮的一匹! 但是实现也是简单粗暴, 纯情的壮汉一枚!private static class LongCache {

private LongCache(){}

static final Long cache[] = new Long[-(-128) + 127 + 1];

static {

for(int i = 0; i < cache.length; i++)

cache[i] = new Long(i - 128);

}

}

1). LongCache实现了Long中的-128到127的缓存

3.4 Character的缓存CharacterCache:

Character表示, 我只有2个字节, 本身是要表示字符的, 表示数字就是兼职交个朋友, 我也很纯情:private static class CharacterCache {

private CharacterCache(){}

static final Character cache[] = new Character[127 + 1];

static {

for (int i = 0; i < cache.length; i++)

cache[i] = new Character((char)i);

}

}

1). CharacterCache实现了Character中的-128到127的缓存

4. 问题有逆转?!

再看个程序:package com.niewj.nio;

/**

* -XX:AutoBoxCacheMax=256

* System.out.println(sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"));

* Created by niewj on 2020/9/19 0:24

*/

public class Test {

public static void main(String[] args) {

Integer i3 = 256;

Integer i4 = 256;

Integer i5 = 257;

Integer i6 = 257;

System.out.println("包装类 256 == 256: "+ (i3 == i4));

System.out.println("包装类 257 == 257: "+ (i5 == i6));

}

}

程序输出:包装类 256 == 256: true

包装类 257 == 257: false

什么??!! 包装类Integer啊! 256==256怎么是true? 257==257怎么又是false?

鬼火?! what the shark! 啥情况?

没错, 我们在main方法的注释里已经标明了, 是在启动时, 加了JVM参数, 设置了:-XX:AutoBoxCacheMax=256

所以此时, Integer缓存的范围就不是 -128到127了, 而是-128到256;

JVM给了Integer类一个操作空间, 可以扩大缓存的范围! 我们通过JVM参数扩大到256了, 所以256比较是同一个对象, 但是257就否了!

4.1 -XX:AutoBoxCacheMax此JVM参数可以扩大Integer里cache的上限值

1). 设置jvm参数: -XX:AutoBoxCacheMax=256package com.niewj.nio;

public class Test {

public static void main(String[] args) {

Integer i3 = 256;

Integer i4 = 256;

Integer i5 = 257;

Integer i6 = 257;

System.out.println("包装类 256 == 256: "+ (i3 == i4));

System.out.println("包装类 257 == 257: "+ (i5 == i6));

System.out.println("java.lang.Integer.IntegerCache.high=\t" + sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"));

}

}

控制台输出:包装类 256 == 256: true

包装类 257 == 257: false

java.lang.Integer.IntegerCache.high= 256

可以看到, 这个参数已经被改了: java.lang.Integer.IntegerCache.high

2). -XX:AutoBoxCacheMax参数改的就是java.lang.Integer.IntegerCache.high的值

4.2 那么, Byte/Short/Long/Character这些类呢? 能扩容么package com.niewj.nio;

public class Test {

public static void main(String[] args) {

Integer i1 = 256;

Integer i2 = 256;

System.out.println("Integer包装类 256 == 256: "+ (i1 == i2));

Short s1 = 256;

Short s2 = 256;

System.out.println("Short包装类 256 == 256: "+ (s1 == s2));

Long l1 = 256L;

Long l2 = 256L;

System.out.println("Long包装类 256 == 256: "+ (l1 == l2));

Character c1 = 256;

Character c2 = 256;

System.out.println("Character包装类 256 == 256: "+ (c1 == c2));

System.out.println("java.lang.Integer.IntegerCache.high=\t" + sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"));

}

}

控制台输出:Integer包装类 256 == 256: true

Short包装类 256 == 256: false

Long包装类 256 == 256: false

Character包装类 256 == 256: false

java.lang.Integer.IntegerCache.high= 256

其实从上面的代码分析我们也可以看出, 除了Integer, 其他的类都没有做参数读取; 都只用了127这个固定值;

1). 只有Integer的缓存127最大值可以参数修改

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值