对于Java初学者而言,可能会对这两个比较方法比较模糊,有的人可能会觉得两个的方法使用起来结果是一样的等。如果你有这样的想法,我建议你来看看这边博客,让你充分了解这两个比较的异同,以及他们底层是如何比较的等。阅读这篇文章之前,我希望你是对Integer和String这两个类是有所了解的,否则可以参考一下博客以加深你对这两个类的理解:

  1、jdk源码阅读笔记-String

  2、jdk源码阅读笔记-Integer

  那么,下面我将使用一些例子来引入本篇博客的主题,看看你能做对多少个题吧!

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的区别吗?的更多相关文章

  1. 夯实Java基础系列6:一文搞懂抽象类和接口,从基础到面试题,揭秘其本质区别!

    目录 抽象类介绍 为什么要用抽象类 一个抽象类小故事 一个抽象类小游戏 接口介绍 接口与类相似点: 接口与类的区别: 接口特性 抽象类和接口的区别 接口的使用: 接口最佳实践:设计模式中的工厂模式 接 ...

  2. 夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战,更有原理分析和源码解析!

    目录 目录 string基础 Java String 类 创建字符串 StringDemo.java 文件代码: String基本用法 创建String对象的常用方法 String中常用的方法,用法如 ...

  3. 夯实Java基础系列7:一文读懂Java 代码块和执行顺序

    目录 Java中的构造方法 构造方法简介 构造方法实例 例 1 例 2 Java中的几种构造方法详解 普通构造方法 默认构造方法 重载构造方法 java子类构造方法调用父类构造方法 Java中的代码块 ...

  4. 夯实Java基础系列10:深入理解Java中的异常体系

    目录 为什么要使用异常 异常基本定义 异常体系 初识异常 异常和错误 异常的处理方式 "不负责任"的throws 纠结的finally throw : JRE也使用的关键字 异常调 ...

  5. 夯实Java基础系列15:Java注解简介和最佳实践

    Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...

  6. Java基础系列--HashMap(JDK1.8)

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10022092.html Java基础系列-HashMap 1.8 概述 HashMap是 ...

  7. 夯实Java基础系列1:Java面向对象三大特性(基础篇)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...

  8. 夯实Java基础系列4:一文了解final关键字的特性、使用方法,以及实现原理

    目录 final使用 final变量 final修饰基本数据类型变量和引用 final类 final关键字的知识点 final关键字的最佳实践 final的用法 关于空白final final内存分配 ...

  9. 夯实Java基础系列5:Java文件和Java包结构

    目录 Java中的包概念 包的作用 package 的目录结构 设置 CLASSPATH 系统变量 常用jar包 java软件包的类型 dt.jar rt.jar *.java文件的奥秘 *.Java ...

随机推荐

  1. 自动生成MyEclipse 安装破解码

    新建一个class 文件,Debug 模式运行一个,输入任意值 ,回车得到破解安装码 代码文件如下: import java.io.*; public class MyEclipseGen { pri ...

  2. Sending forms through JavaScript

    https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript As in the ...

  3. 如何在 Docker 容器中运行 Kali Linux 2.0

    https://linux.cn/article-6103-1.html Kali Linux 是一个对于安全测试人员和白帽的一个知名操作系统.它带有大量安全相关的程序,这让它很容易用于渗透测试.最近 ...

  4. 从Freelancer的热门Skill看看你应该学什么?

    以下数据是2012-1-31号数据. Websites, IT & Software: PHP (2402)HTML (1639)SEO(877)MySQL (836)Link Buildin ...

  5. FFmpeg and x264 Encoding Guide

    https://trac.ffmpeg.org/wiki/Encode/H.264 FFmpeg and H.264 Encoding Guide Contents Constant Rate Fac ...

  6. Django signals机制的几个简单问题

    1.Django signals机制不是异步执行,是同步执行,所以需要异步执行的耗时任务不能用这个. 2.异步耗时任务不用这个,那些用signals?主要是解耦那些多次重复场合被调用的函数.直接用事件 ...

  7. Android Third Party Libraries and SDK's

    http://javatechig.com/Android/android-third-party-libraries-sdks Over past few years, the age of mob ...

  8. 使用ASP.NET SignalR实现一个简单的聊天室

    前言 距离我写上一篇博客已经又过了一年半载了,时间过得很快,一眨眼,就把人变得沧桑了许多.青春是短暂的,知识是无限的.要用短暂的青春,去学无穷无尽的知识,及时当勉励,岁月不待人.今天写个随笔小结记录一 ...

  9. PCA算法和python实现

    第十三章 利用PCA来简化数据 一.降维技术 当数据的特征很多的时候,我们把一个特征看做是一维的话,我们数据就有很高的维度.高维数据会带来计算困难等一系列的问题,因此我们需要进行降维.降维的好处有很多 ...

  10. .net 弹出消息框后,页面样式变乱

    点击按钮,执行提交操作,弹出消息框后,页面的样式变乱,解决方法: 首先,确定使用的css样式正确,页面中的宽高值保持规范统一: 然后,弹出框避免使用Response.Write(),如下所示 Resp ...