详解Java中==和equals()的区别
众所周知,在 Java 编程中,程序员通常会使用==
或equals()
来简单的比较地址,内容是否相等。而这两者之间的使用区别,对于初学 Java 的同学来说可能会比较迷糊。我将根据下面的几段示例程序,来对这两种比较方法进行分析,供大家参考:
private static void method1() {
Integer n1 = new Integer(5);
Integer n2 = new Integer(5);
System.out.println(n1.equals(n2));// true
System.out.println(n1 == n2);// false
}
在method1()
中,第一个的输出打印结果如我所料,equals()
比较两者的内容,输出结果会是true
,但是第二个打印输出结果,如果是在我刚接触 Java 时,肯定会毅然决然的认为这条输出的结果应该是true
。但事实是,尽管n1 和 n2 看起来内容相同,但是程序执行出来的结果却是false
。
翻阅《 Java 编程思想(第四版)》,在书中有这么一段话:
== 和 != 比较的就是对象的引用。
如果想比较两个对象的实际内容是否相同,必须使用所有对象都使用的特殊方法 equals() 方法。但这个方法不适用于“基本类型”,基本类型直接使用 == 或 != 即可。
通过书里的这段话我们进行分析,在method1()
方法里,尽管 n1,n2 两个对象的内容是相等的,但是它们本质上是属于两个创建出来的不同的对象。因此,在method1()
中,两个不同的对象它们所引用的地址当然是不相同的,故method1()
的第二个输出结果为false
。
private static void method2() {
Integer n3 = 127;
Integer n4 = 127;
Integer n5 = 128;
Integer n6 = 128;
System.out.println(n3 == n4);// true
System.out.println(n5 == n6);// false
}
在method2()
中可以看到,这里的写法不是通过 new 形式来创建 Integer 对象了 ,而是通过自动装箱方式创建一个 Integer 对象。何谓自动装箱,通俗的解释就是自动将基本数据类型转换为包装器类型。记得我在method1()
中写道:== 比较的就是对象的引用。在这里 n3 ,n4 属于两个不同的对象,通过 ==
比较的是两个对象的引用,理应输出的结果是false。那么结果为什么是true
呢?
为了便于分析,我们可以仅在代码里保留一行代码。
public class Equivalence {
public static void main(String[] args) {
Integer n3 = 127;
}
}
通过编译该 java 文件后,在控制台窗口中切换到其编译后输出的 *.class字节码
文件的位置,输入javap -c "文件名.class"
对其进行反编译。我们来看看保留的这段代码执行编译中干了什么事情:
从打印输出的内容截图里,我们可以知道系统当使用 Integer 自动装箱时,系统会帮我们会调用Integer.valueOf()
方法,我们可以查看下该方法的源码。
public final class Integer extends Number implements Comparable<Integer> {
// ...
public static Integer valueOf(int i) {
// 对传进来的数值进行比较
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
/**
* Integer的内部类,用于缓存 -128 ~ 127的数值
*/
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() {}
}
}
通过查阅源码注释(本文未展示),这个方法是在JDK 1.5
时加入的。当执行Integer.valueOf()
方法时,会将传进来的数值与IntegerCache.low
和IntegerCache.high
进行比较。为了避免多次创建浪费资源,通过IntegerCache
这个 Integer 的缓存内部类,将-128 ~ 127
的数值缓存起来。
也就是说,当我们使用 Integer 进行自动装箱操作时,会将装箱的数值与缓存的数值进行比较,如果在该缓存范围内,则会返回一个已经创建好的 Integer 对象,反之将会重新创建一个 Integer 对象。这么一来,也就可以解释的通:为什么 n3 、n4数值相等,n4、n5数值也同样相等,输出的结果却是不同的原因了。
上述内容,我们仅是通过 Integer 包装类的源码对==
和equals()
两种比较方式进行分析。实际上,不同的包装类,所执行出的效果也不尽相同。若想深入了解,大家可以查看我文末附上的参考文章链接。
接下来我们再通过代码示例,对equals()
进行分析。
public class Equivalence {
public static void main(String[] args) {
method3();
}
private static void method3() {
Value v1 = new Value(100);
Value v2 = new Value(100);
String s1 = new String("smallmin");
String s2 = new String("smallmin");
System.out.println(v1.equals(v2));// false
System.out.println(s1.equals(s2));// true
}
}
class Value {
int i;
public Value(int i) {
super();
this.i = i;
}
}
记得我们在method1()
中讲过,比较两个对象的实际内容是否相同,必须使用所有对象都使用的特殊方法 equals() 方法。那么上面示例代码中,为什么v1 与 v2 比较输出结果会是false
,而 s1 与 s2 比较出的结果却是true
呢?
在method1()
中我们 Integer 对象之间通过equals()
比较以及本例中,String
对象间通过equals()
输出的比较结果都是true
(对象内容相等的前提下)的原因是,Integer 和 String 等类中,都对equals()
进行了重写,因文章篇幅原因故不再逐一附上源码。
而v1 与 v2 是我们自己创建的对象,没有重写equals()
方法,当调用该方法时执行的是父类Object
的equals()
方法。而Object
的equals()
方法通过查看源码可得知,其实它是比较两者之间的引用地址。v1 和 v2 尽管对象的内容相同,但是它们分别来自不同的对象,引用地址当然不同,故两者比较的结果是false
。
public boolean equals(Object obj) {
return (this == obj);
}
总结:
- 基本数据类型之间比较,可直接使用
==
进行比较。 - 当比较两个对象引用地址是否为同个地址时,使用
==
进行比较。 - 在重写了
equals()
的前提下,比较对象内容或者其他自定义的比较方法时,使用equals()
比较。
本文参考文章:https://www.cnblogs.com/wang-yaz/p/8516151.html
关于自动装箱与拆箱的细节可以看看这篇文章,感谢作者提供好的思路和讲解。
详解Java中==和equals()的区别的更多相关文章
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
- 第十八节:详解Java抽象类和接口的区别
前言 对于面向对象编程来说,抽象是它的特征之一. 在Java中,实现抽象的机制分两种,一为抽象类,二为接口. 抽象类为abstract class,接口为Interface. 今天来学习一下Java中 ...
- 详解Java中对象的软、弱和虚引用的区别
对于大部分的对象而言,程序里会有一个引用变量来引用该对象,这是最常见的引用方法.除此之外,java.lang.ref包下还提供了3个类:SoftReference.WeakReference和Phan ...
- 详解Java中的字符串
字符串常量池详解 在深入学习字符串类之前, 我们先搞懂JVM是怎样处理新生字符串的. 当你知道字符串的初始化细节后, 再去写String s = "hello"或String s ...
- java 中 ==和equals 的区别
Java中equals和==的区别 java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolea ...
- JAVA中“==”与equals()方法区别
equals 方法是 java.lang.Object 类的方法 有两种用法说明: ()对于字符串变量来说,使用"=="和"equals()"方法比较字符串时, ...
- 【Java学习笔记之三十三】详解Java中try,catch,finally的用法及分析
这一篇我们将会介绍java中try,catch,finally的用法 以下先给出try,catch用法: try { //需要被检测的异常代码 } catch(Exception e) { //异常处 ...
- Java中==与equals的区别及理解
区别: "==" 比较的是两个引用在内存中指向的是不是同一对象(即同一内存空间),也就是说在内存空间中的存储位置是否一致. 如果两个对象的引用相同时(指向同一对象时)," ...
- Java中==与equals()的区别
声明转载来源:http://blog.csdn.net/striverli/article/details/52997927 ==号和equals()方法都是比较是否相等的方法,那它们有什么区别和联系 ...
随机推荐
- JavaScript new 关键词解析及原生实现 new
java里面,new 运算符是用来实例化一个类,从而在内存中分配一个实例对象. 但在 javascript 中,原型语言没类,只有对象与原型链继承 JavaScript 中 new 表达式的作用是生成 ...
- dockerfile中ENTRYPOINT与CMD的结合
一.写在前面 我们在上篇小作文docker容器dockerfile详解对中dockerfile有了比较全面的认识,我们也提到ENTRYPOINT和CMD都可以指定容器启动命令.因为这两个命令是掌握do ...
- noip9
T1 本次考试最水的一道题,然而我sb,前一个小时,找了一大堆跟题目无关的性质,干脆打了个20pts的表,然后就走了,最后几分钟才看出来,匆匆码出来,结果段错误,然后考试就结束了. 好吧,段错误是UB ...
- Windows安装Linux虚拟机(CentOS7)
一.在电脑上安装虚拟机,百度搜索vmware,下载后傻瓜式安装即可. 二.CentOS下载,阿里云镜像:http://mirrors.aliyun.com/centos/7/isos/x86_64/. ...
- spring4整合hibernate5以及出现的问题解决办法
每一次的学习,都是一小步一小步的进行的,学习语言,重要的是能把hello world写出来 以及在学习过程中出现的问题能够及时的记录并总结 spring目前最新的版本是4.3,而hibernate是5 ...
- QT 中的QTableWidget
- Springboot使用MatrixVariable 注解
根据 URI 规范 RFC 3986 中 URL 的定义,路径片段中可以可以包含键值对.规范中没对对应的术语.一般 "URL 路径参数" 可以被应用,尽管更加独特的 &qu ...
- 【IDE】Sublime Text 3 使用配置
1 安装 首先现在安装Sublime Text 3,直接官网下载(http://www.sublimetext.com/3),也可以在其他地方下载,安装完成后进行破解 菜单栏Help - Enter ...
- Spring中常用重要的接口
Spring (ApplicationContext 初始化Bean的方法 refresh()) public void refresh() throws BeansException, Illega ...
- JDBC基础篇(MYSQL)——自定义JDBCUtil工具类
package util; import java.io.File; import java.io.InputStream; import java.sql.Connection; import ja ...