漫画:Integer 竟然有 6 种比较方式?









代码测试
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = 127;
Integer i2 = 127;
System.out.println(i1 == i2);
Integer i3 = 128;
Integer i4 = 128;
System.out.println(i3 == i4);
}
}
以上代码的执行结果为:
true false




首先,当我们将以上的测试代码编译为字节码(.class)之后,编码的代码如下:
public class IntegerTest {
public static void main(String[] paramArrayOfString) {
Integer integer1 = Integer.valueOf(127);
Integer integer2 = Integer.valueOf(127);
System.out.println((integer1 == integer2));
Integer integer3 = Integer.valueOf(128);
Integer integer4 = Integer.valueOf(128);
System.out.println((integer3 == integer4));
}
}
可以看出在创建 Integer 时使用到了 valueOf,它的实现源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
从上述源码中可以看出这个方法中使用了 IntegerCache,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() {}
}
从上述源码可以看出,在 Integer 的取值在 -128 到 127 之间时,它会复用已有的对象,因此在 i1(127)和 i2 使用 == 对比时值才会为 true,而当取值变为 128 时,则执行的结果为 false。
这一点其实在阿里巴巴的《Java开发手册》中也有相应的规定,规定的内容如下:
【强制】所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在 -128 至 127 之间的赋值,Integer 对象是在 IntegerCache.cache 产生, 会复用已有对象,这个区间内的 Integer 值可以直接使用 == 进行判断,但是这个区间之外的所有数据,都 会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
注意事项
不仅如此,当我们使用 new Integer 时,无论值为多少都不能使用 == 比较,示例代码如下:
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2);
}
}
以上代码的执行结果为:
false
这是因为 new Integer 方法并没有使用到 IntegerCache,而是直接创建了新对象,因此就不能用 == 比较了。
小贴士:== 是用来直接比对两个对象的引用是否相同的,而 equals 则是用来对比两个对象的值是否相同的。


其他比较方式
compareTo
因为 Integer 类实现了 Comparable 接口,因此我们可以使用 compareTo 来对比两个值的大小,实现源码如下:
public final class Integer extends Number implements Comparable<Integer> {
// 忽略其他内容
}
compareTo 的使用如下:
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.println(i1.compareTo(i2));
}
}
以上代码的执行结果为:
0
compareTo 的源码如下:
public int compareTo(Integer anotherInteger) {
return compare(this.value, anotherInteger.value);
}
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
由此可以看出 compareTo 的返回值总共有三个:-1、0、1,其中 -1 表示前一值小于后一个值;0 表示两个值相等;1 表示前一个值大于后一个值,因此我们用它来比较两个 Integer 的值是否相等。
直接运算
compareTo 方法给我们了一个启发,我们可以直接将两个值进行相减,如果相减的值等于 0,则说明对比的两个值是相同的,示例代码如下:
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.println((i1 - i2) == 0);
}
}
以上代码的执行结果为:
true
intValue
我们可以使用 intValue 得到 Integer 的 int 值,然后再使用 == 进行比较,示例代码如下:
public class IntegerTest {
public static void main(String[] args) {
Integer i = 558;
Integer i2 = 558;
System.out.println(i.intValue() == i2.intValue());
}
}
以上代码的执行结果为:
true
异或
异或是一个数学运算符,它应用于逻辑运算。在计算机中如果 a、b 两个值不相同,则异或结果为 1;如果 a、b 两个值相同,异或结果为 0。
比如:
- 1 异或 0=1
- 0 异或 0=0
- 1 异或 1=0
异或实现示例如下:
public class IntegerTest {
public static void main(String[] args) {
Integer i = 558;
Integer i2 = 558;
System.out.println((i ^ i2) == 0);
}
}
以上代码的执行结果为:
true
扩展知识:IntegerCache 值域修改
IntegerCache 默认的取值范围为 -128 到 127,但我们可以通过设置启动参数来调整 IntegerCache 的最大缓存值,比如我们可以配置虚拟机的启动参数 -XX:AutoBoxCacheMax=1000,此配置表示将缓存的最大值设置为 1000,如果是 Idea 的配置如下:
此时我们编写一个测试代码:
public class IntegerTest {
public static void main(String[] args) {
Integer i1 = 999;
Integer i2 = 999;
System.out.println(i1 == i2);
}
}
以上代码的执行结果为:
true
从运行的结果可以看出 IntegerCache 的取值范围被成功的更改了。
总结
本文我们介绍了 Integer 的 6 种比较方式:==、equals、compareTo、直接运算,而 == 方式并不能用于 Integer 的比较,它只适用于非 new Integer 的一定范围内(-128~127),而后 5 种方式都可以正常用于 Integer 的比较,其中 equals 的比较方式是最为常用的。



互动话题
除了以上几种比较方式之外,你还知道其他的比较方式吗?欢迎评论区补充留言。
漫画:Integer 竟然有 6 种比较方式?的更多相关文章
- Web APi之认证(Authentication)两种实现方式后续【三】(十五)
前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络 ...
- java笔记--关于线程同步(7种同步方式)
关于线程同步(7种方式) --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897440.html"谢谢-- 为何要使用同步? ...
- Map三种遍历方式
Map三种遍历方式 package decorator; import java.util.Collection; import java.util.HashMap; import java.util ...
- Java多线程的三种实现方式
java多线程的三种实现方式 一.继承Thread类 二.实现Runnable接口 三.使用ExecutorService, Callable, Future 无论是通过继承Thread类还是实现Ru ...
- Android数据的四种存储方式
作为一个完成的应用程序,数据存储操作是必不可少的.因此,Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File. ...
- Android开发_Android数据的四种存储方式
Android系统一共提供了四种数据存储方式.分别是:SharePreference.SQLite.Content Provider和File.由于Android系统中,数据基本都是私有的的,都是存放 ...
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (四) —— ContentProvider
ContentProvider是安卓平台中,在不同应用程序之间实现数据共享的一种机制.一个应用程序如果需要让别的程序可以操作自己的数据,即可采用这种机制.并且此种方式忽略了底层的数据存储实现,Cont ...
- Android数据的四种存储方式SharedPreferences、SQLite、Content Provider和File (二) —— SQLite
SQLite是一种转为嵌入式设备设计的轻型数据库,其只有五种数据类型,分别是: NULL: 空值 INTEGER: 整数 REAL: 浮点数 TEXT: 字符串 BLOB: 大数据 在SQLite中, ...
- Android平台中实现对XML的三种解析方式
本文介绍在Android平台中实现对XML的三种解析方式. XML在各种开发中都广泛应用,Android也不例外.作为承载数据的一个重要角色,如何读写XML成为Android开发中一项重要的技能. 在 ...
随机推荐
- 第二个hibernate Annotation版本的helloworld
经过第一次的 hibernate 我发现每一个数据库表都对应了一个类,并且每一个类都要新建一个文件进行配置 很麻烦! 于是便出现了Annotation版本的hibernate. 具体如下: 1.同 ...
- Base-64字符串无效,The input is not a valid Base-64 string as it contains a non-base 64 character
base64规则: * 字符串只可能包含A-Z,a-z,0-9,+,/,=字符* 字符串长度是4的倍数* =只会出现在字符串最后,可能没有或者一个等号或者两个等号 首先,C# 做上传文件的时候,需要替 ...
- spring源码解读-aop
aop是指面向切面编程,ProxyFactoryBean是spring aop的底层实现与源头,为什么这么说呢?首先我们看一段配置: 1.target是目标对象,需要对其进行切面增强 2.proxyI ...
- v-else-if(v-show)
<div id="app"> <div v-if="type === 'A'"> A </div> <div v-el ...
- 君荣一卡通软件mysql转sqlserver 教程
Mysql数据库转sql数据库方法 注意:新建的SQL数据库一得先登录一次后再做迁移!!!!特别注意 如果客户以前安装的是mysql数据库,现在希望把mysql数据库转换的sql数据库,方法如下: 1 ...
- Eureka加了secsecurity后注册失败
报错信息: com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known ...
- c++_primer_第4版目录
https://vdisk.weibo.com/s/BN_NALmbbBH01 第1章 快速入门1.1 编写简单的C++程序1.2 初窥输入/输出1.2.1 标准输入与输出对象1.2.2 一个使用IO ...
- upd套接字服务器与客户端交互C++代码示范
upd套接字服务器与客户端交互C++代码示范 // vc2_2_4UDPserver_Txwtech.cpp : 定义控制台应用程序的入口点. //服务器端 #include "StdAfx ...
- Beta冲刺<2/10>
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta冲刺 这个作业的目标 Beta冲刺--第二天(05.20) 作业正文 如下 其他参考文献 ... B ...
- CentOS7 开机进入emergency mode
今天突然操作了一下磁盘挂载,然后系统启动之后,就直接进入emergency模式了,然后只能输入密码进行救援,截图如下: 突然想了一下最近的一次操作,是因为要挂在镜像,然后每次开机都要挂载一次,觉得比较 ...