前言

==和equals是我们面试中经常会碰到的问题。那么它们之间有什么联系和区别呢?今天我们就来聊聊吧!

问题

这里先抛出一些比较典型笔试问题:

int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
String str4 = "abc";
System.out.println(x == y); // 输出?
System.out.println(str1 == str2); // 输出?
System.out.println(str1.equals(str2)); // 输出?
System.out.println(str3 == str4); // 输出?
System.out.println(str1 == str3); // 输出?
System.out.println(str1.equals(str3)); // 输出? Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出?
System.out.println(f3 == f4);// 输出?

正文

​ 我们通常就是说"=="用来判断两个变量之间的的值是否相等。变量又分为基本数据类型变量和引用类型。如果是基本数据类型的变量直接比较值而引用类型要比较对应的引用的内存的首地址。而equals方法 通俗来说就是用来比较两个对象长得是否一样。判断两个对象的某些特征(内容)是否一样。实际上就是调用对象的equals方法进行比较。那么我们来看看equals方法吧!

​ equals方法其实是属于Object类的方法。因为Object类是所有类的直接或间接父类,也就是说所有的类中的equals()方法都继承自Object类,而通过源码我们发现,Object类中equals()方法底层实现其实就是是"=="号。

public boolean equals(Object obj) {
return (this == obj);
}

那么,在所有没有重写equals()方法的类中,调用equals()方法其实和使用"=="号的效果一样,也是比较的对象地址值,然而,Java提供的所有类中,绝大多数类都重写了equals()方法,重写后的equals()方法一般都是比较两个对象的值,比如String类,Date类,基本数据类型的包装类等。可以看哈String类的源码:

    public boolean equals(Object var1) {
if (this == var1) {
return true;
} else {
if (var1 instanceof String) {
String var2 = (String)var1;
int var3 = this.value.length;
if (var3 == var2.value.length) {
char[] var4 = this.value;
char[] var5 = var2.value;
for(int var6 = 0; var3-- != 0; ++var6) {
if (var4[var6] != var5[var6]) {
return false;
}
}
return true;
}
}
return false;
}
}

解决

看了上面的描述,相信你可以做对或者回答起大多数这类的问题。但是还需要注意以下两点:

String str3 = "abc";
String str4 = "abc";
System.out.println(str3 == str4); // 输出true
  • 这里为什么会是true呢?按理说str3和str4是两个对象,"=="比较的是地址,应该会是false才对。如果你是这么想的,那你就不是很了解String类。String类,我们都知道它是不可变的字符序列,存储在常量池中,所以当你声明了一个str3="abc"时,就会在常量池中开辟一个内存空间来存放"abc",下次再声明时,就会在常量池中去找,有,就直接把当前地址赋给变量,没有,就再创建。因此,此处的str3和str4是指向的同一个内存地址。
Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出true
System.out.println(f3 == f4);// 输出false
  • 看到上面的答案是不是感到十分的诧异。其实这里隐藏着一个知识点。就是包装类的缓存问题。下面简单描述一下:

    整型、char类型所对应的包装类,在自动装箱时,对于-128~127之间的值会进行缓存处理。当然其目的就是提高效率。

    缓存处理的原理为:如果数据在-128~127这个区间,那么在类加载时就已经为该区间的每个数值创建了对象,并将这256个对象存放到一个名为cache的数组中。每当自动装箱过程发生时(或者手动调用valueOf()时),就会先判断数据是否在该区间,如果在则直接获取数组中对应的包装类对象的引用,如果不在该区间,则会通过new调用包装类的构造方法来创建对象。

    此处以Integer类为例,源码参考:

    public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i); // 超过范围就是new的Integer对象
    }

    这段代码中我们需要解释下面几个问题:

    1. IntegerCache类为Integer类的一个静态内部类,仅供Integer类使用,作用就是初始化数组cache的,这个过程会在类加载时完成。感兴趣可以去看哈源码,这里就不再粘贴了。
    2. 一般情况下 IntegerCache.low为-128,IntegerCache.high为127,IntegerCache.cache为内部类的一个静态属性。

看到这,相信你对上面抛出的问题,已经可以迎刃而解。答案参考:

		int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
String str4 = "abc";
System.out.println(x == y); // 输出true
System.out.println(str1 == str2); // 输出false
System.out.println(str1.equals(str2)); // 输出true
System.out.println(str3 == str4); // 输出true
System.out.println(str1 == str3); // 输出false
System.out.println(str1.equals(str3)); // 输出true Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2);// 输出true
System.out.println(f3 == f4);// 输出false

公众号:良许Linux

有收获?希望老铁们来个三连击,给更多的人看到这篇文章

最新文章

  1. Entity Framework 6 Recipes 2nd Edition 译 -&gt; 目录 -持续更新
  2. Hawk使用补充说明
  3. YbSoftwareFactory 代码生成插件【十六】:Web 下灵活、强大的审批流程实现(含流程控制组件、流程设计器和表单设计器)
  4. Handlebars模板库浅析
  5. jdk的设置及安装android studio提示does not point to a valid jvm问题
  6. Sharepoint学习笔记—习题系列--70-573习题解析 -(Q77-Q80)
  7. 【风马一族_Android】Android 前端内容1
  8. 20169210《Linux内核原理与分析》课程总结
  9. 创建第一个freemarker
  10. atan(正切函数)
  11. [LeetCode]题解(python):131-Palindrome Partitioning
  12. oracle命令大全
  13. C++输出数据到txt
  14. Python小练习
  15. Elasticsearch集成HanLP分词器
  16. Linux内存管理学习3 —— head.S中的段页表的建立
  17. composer - No business network has been specified for this connection 解决方案
  18. 正确理解java编译时,运行时以及构建时这三个概念
  19. C#读取Excel日期时间
  20. Linux命令之sync - 强制将内存中的文件缓冲内容写到磁盘

热门文章

  1. Java实现 LeetCode 633 平方数之和(暴力大法)
  2. Java实现 LeetCode 324 摆动排序 II
  3. Java实现 LeetCode 224 基本计算器
  4. 第九届蓝桥杯JavaB组省赛真题
  5. Mybatis多表操作
  6. sql server 连接种类
  7. vue cli3 创建的项目中eslint 配置 问题的解决
  8. .Net Core实战之基于角色的访问控制的设计
  9. synchronized 和 java.util.concurrent.locks.Lock 的异同 ?
  10. @loj - 2987@ 「CTSC2016」时空旅行