Java基础系列之你真的懂==与equals的区别吗?
对于Java初学者而言,可能会对这两个比较方法比较模糊,有的人可能会觉得两个的方法使用起来结果是一样的等。如果你有这样的想法,我建议你来看看这边博客,让你充分了解这两个比较的异同,以及他们底层是如何比较的等。阅读这篇文章之前,我希望你是对Integer和String这两个类是有所了解的,否则可以参考一下博客以加深你对这两个类的理解:
那么,下面我将使用一些例子来引入本篇博客的主题,看看你能做对多少个题吧!
public static void main(String[] args) {
    int i1 = 8;
    int i2 = 8;
    Integer i3 = 8;
    Integer i4 = new Integer(8);
    Integer i41 = new Integer(8);
    Integer i5 = 129;
    Integer i6 = 129;
    int i7 = 129;
    System.out.print(i1 == i2);
    System.out.print(" ");
    System.out.print(i1 == i3);
    System.out.print(" ");
    System.out.print(i1 == i4);
    System.out.print(" ");
    System.out.print(i4 == i41);
    System.out.print(" ");
    System.out.print(i5 == i6);
    System.out.print(" ");
    System.out.print(i5 == i7);
    System.out.print(" ");
    System.out.print(i5.equals(i7));
}
上面运行的结果为 true true true false false true true,第一个i1 == i2 结果为true ,这个可以理解,因为两个都是int基本数据类型,并且值相等;第二个比较 i1 == i3 结果也为true,i3为int基本数据类型对应的引用类型,那么它们为什么相等呢?这个我们需要怎么去验证呢?其实可以通过字节码看编译器是如何执行这些代码就可以了;通过字节码发现,在执行 == 的时候i3变量是先执行intValue()这方法,这个方法的作用就是返回Integer类型对应的int值。所以 i1 和i3的比较最终还是变成了 i1 == i2的比较。
  字节码文件:
intValue方法的源码:
/**
* Returns the value of this {@code Integer} as an
* {@code int}.
*/
public int intValue() {
return value;
}
直接返回了 value这个变量,而这个变量就是int类型的全局变量:
/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
我们再回到上面i1 == i4 的问题,i1是基本类型,i4是引用类型,其实还是回到了第二种情况,所以他们还是true。
i4 == i41 两个都是引用类型,并且都是用了new的关键字,我们知道只要调用new关键字那么他们的引用地址肯定不一样,他们的结果返回了false,说明引用类型使用==比较时比较的是他们的内存地址,而不是字面值。
i5 == i6 : 两个都是引用类型,并且值相等,但是结果是false,通过看字节码可以知道,编译器在编译的是时候,这种直接赋值的操作实际上调用了Integer中的valueOf方法,不清楚这个方法的同学建议看一下上面关于Integer的博客。Integer这个类为了提高速度,缓存了-127 至 128 的数,当调用valueOf的时候,如果传进来的数在这个范围之内,那么直接返回缓存的数据,否则new一个对象出来,然后返回。这个例子中,两个值都超出返回,所以都new了一个对象。这个是在开发过程中经常遇到的坑,解决办法是使用equals方法,这个方法已经被重写了,其过程是将引用类型转成基本类型,然后使用 == 来比较大小;
i5 == i7: 一个基本数据类型,一个引用类型,且超出缓存范围,结果为true。这个不难理解,引用类型在编译的时候会自动拆箱,所以最后比较的是基本类型,所以为true。
i5.equals(i7): 上面也有提到Integer已经重写了equals方法,所以跟上一种情况是一致的,为true。
在String类中也会有比较多的面试会遇到,比如说下面代码示例:
 public static void main(String[] args) {
        String str1 = "aa";
        String str2 = "aa";
        String str3 = new String("aa");
        System.out.println(str1 == str2);//true
        System.out.println(str1 == str3);//false
        System.out.println(str1.equals(str3));//true
    }
看到这里,可能会有同学会问,String每创建一次就会生成一个新对象,所以他们的内存地址肯定不一样,但是str1 == str2 返回true,这说明明 == 比较的是字面量吗?答案是否定的,String在我们日常开发中使用的频率最高的类,频繁的创建对象势必对应用的性能有一定的影响,java官方为了提高性能,每次使用字面量声明字符串时都会先向缓存池中查找池中是否已存在该对象,如果有则直接引用该对象,如果没有则new一个对象出来,然后将该对象放入缓存池中。上面str1 和str2因为字面量是相同的,所以他们共用缓存池中的一个对象,所以他们指向的内存地址是一样的,故为true;
str3是直接new出来的,所以他是不经过缓存池的,因此str1 和 str3是不同的。
String 的equals方法也已经重写了object的equals方法,它首先比较两个字符串的内存地址,不一样了才对两个字符串字面量进行比较。
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
划重点:== 与 equals 的区别
对于未重写Object类中的equals方法,两者的作用是一样的,因为Object的equals方法也是使用 == 来判断两个对象是否相等的。
== 操作符对于基本类型数据则比较的是他们的字面量的值是否相等,只要有一个是基本类型,那么另一个如果的封装类型,则会自动拆箱;对于两个类型都是引用类型,则比较的是两个对象的内存地址的值是否相等。
equals方法如果未被重写,与 == 无异。一般地,我们都会重写Object中equals方法,比如上面的Integer和String都重写的equals方法,该方法比较的是字面量的值是否相等,有别于 ==。
  欢迎大家关注公众号: 【java解忧杂货铺】,里面会不定时发布一些技术博客;关注即可免费领取大量最新,最流行的技术教学视频:



Java基础系列之你真的懂==与equals的区别吗?的更多相关文章
- 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!
		
目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接 ...
 - 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!
		
目录 目录 string基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如 ...
 - 夯实Java基础系列7:一文读懂Java 代码块和执行顺序
		
目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...
 - 夯实Java基础系列10:深入理解Java中的异常体系
		
目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调 ...
 - 夯实Java基础系列15:Java注解简介和最佳实践
		
Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...
 - Java基础系列--HashMap(JDK1.8)
		
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10022092.html Java基础系列-HashMap 1.8 概述 HashMap是 ...
 - 夯实Java基础系列1:Java面向对象三大特性(基础篇)
		
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...
 - 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理
		
目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 ...
 - 夯实Java基础系列5:Java文件和Java包结构
		
目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...
 
随机推荐
- golang基础- ElasticSearch搜索引擎、kibana可视化工具、向ES输出数据
			
转载自:https://blog.csdn.net/u013210620/article/details/78647366 安装ElasticSearch ElasticSearch是一个基于Luce ...
 - python---数据类型---列表
			
#列表: name = ["lc","pxm","pt"] print('------------',name[2],"----- ...
 - Storyboard中ViewController加载的四种方式
			
这个总结来自于<Programming iOS 10>一书: 1.storyboard的初始化ViewController,通过方法instantiateInitialViewContro ...
 - webstorm配置eslint【标记错误,修复错误】
			
项目中经常用到eslint语法,结合个人经验,用webstorm配置eslint "文件"->"默认设置"->"语言&框架&quo ...
 - netcore入门-基础
			
.NETCORE1.0出来了,咦不错,什么开源,跨平台的,观望下等2.0:我擦2.0出来了可以学习了,截止到目前2.1都快出来了,是时候学习一下了. 先建一个webapi项目,从简单的demo开始 l ...
 - 网络传输数据封装详解(IP,UDP,TCP)
			
IP数据包也叫IP报文分组,传输在ISO网络7层结构中的网络层,它由IP报文头和IP报文用户数据组成,IP报文头的长度一般在20到60个字节之间,而一个IP分组的最大长度则不能超过65535个字节. ...
 - 洛谷 P2491 解题报告
			
P2491 消防 题目描述 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个 ...
 - 如何在自定义组件中使用v-model
			
文章属于速记,有错误欢迎指出.风格什么的不喜勿喷. 先来一个组件,不用vue-model,正常父子通信 <!-- parent --> <template> <div c ...
 - shell 常用命令语法简介
			
一.grep用法 ************************************** ++++++用一些特殊的函数来处理参数++++++ *$# 传递给函数的参数个数 *$* 显示所有传递给 ...
 - 使用JWT的OAuth2的SSO分析
			
参考:https://github.com/spring-guides/tut-spring-security-and-angular-js/blob/master/oauth2/README.ado ...