1、前言

我们在学习Java的时候,看到==、equals()就认为比较简单,随便看了一眼就过了,其实你并没有深入去了解二者的区别。这个问题在面试的时候出现的频率比较高,而且据统计有85%的人理直气壮的答错。所以理解==与equals()的区别很有必要。

2、==运算符

==可以使用在基本数据类型变量和引用数据类型变量中。

1、如果比较的是基本数据类型变量:比较两个变量的数值是否相等(数据类型不一定要相等,只看值,因为会类型自动提升!);

2、如果比较的是引用数据类型变量:比较两个对象的地址值是否相等。

下面看一下案例:

public class Test {
    public static void main(String[] args) {
        int a=10;
        int b=10;
        double c=10.00;
        System.out.println(a==b);//true
        System.out.println(a==c);//true

        String str1="123";
        String str2="123";
        System.out.println(str1==str2);//true

        String str3=new String("123");
        String str4=new String("123");
        System.out.println(str3==str4);//false
    }
}

结果为:true、true、true、false。前面两个为true的结果非常容易理解,但是第三个为true,第四个为false,而它们都是String引用类型,为什么不一样呢?

分析原因:

对于8种基本数据类型(byte,short,char,int,float,double,long,boolean)的值而言,它们都是存储在常量池中,而str1、str2的字符串 "123" 也同样在常量池中,而一个常量只会对应一个地址,因此不管是再多的数据都只会存储一个地址,所以所有他们的引用都是指向的同一块地址,因此基本数据类型和String常量是可以直接通过==来直接比较的。

而str3、str4分别在堆内存中创建的两个对象,地址值自然就不相同了。

3、equals()方法

equals()是一个方法,不是数据类型,所以他只适用于引用数据类型。

该方法主要用于比较两个对象的内容是否相等。其实这样的说法是不准确的。首先我们来看看在Object类中定义的equals方法:

可以看到,在Object类型的equals方法是直接通过==来比较的,和==是没有任何区别的。

那么为什么又要说equlas和==的区别呢?是因为所有的类都直接或间接地继承自java.lang.Object类,因此我们可以通过重写equals方法来实现我们自己想要的比较方法。

我们创建一个Person类来测试,先不重写父类的equals()方法:

public class Test {
    public static void main(String[] args) {
        Person person1=new Person("菜徐坤",21);
        Person person2=new Person("菜徐坤",21);
        System.out.println(person1.equals(person2));
    }
}

class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

毫无疑问,输出的结果肯定是false,因为没有重写父类的equals()方法,从而调用了父类的,而父类的equals()方法是用==判断的。

然后我们重写父类的equals()方法:

public class Test {
    public static void main(String[] args) {
        Person person1=new Person("菜徐坤",21);
        Person person2=new Person("菜徐坤",21);
        System.out.println(person1.equals(person2));
    }
}

class Person{
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Person person = (Person) o;

        if (age != person.age) return false;
        return name != null ? name.equals(person.name) : person.name == null;
    }
}

重写之后输出就是true了,因为比较的对象的内容。

实际上,像String、Date、Math、File、包装类等大部分类都重写了Object的equals()方法。重写以后,就不是比较两个对象的地址值是否相同了,而是比较两个对象里面的内容是否相等。

下面我们来看一下String类重写的equals()方法:

* @see  #compareTo(String)
     * @see  #equalsIgnoreCase(String)
     */
    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;
    }

可以看到重写的方法内用char[] 数组进行一个一个的比较,并不是用==进行比较,。

我们在重写equals()方法时必须要遵循如下几个规则:

  1. 自反性:x.equals(x)必须返回是true。
  2. 对称性:如果x.equals(y),返回时true,那么y.equals(x)也必定返回为true。
  3. 传递性:如果x.equals(y)返回的true,而且y.equals(z)返回是true,那么z.equals(x)返回的也是true。
  4. 一致性:如果x.equals(y)返回是true,只要x和y的内容一直不变,不管重复x.equals(y)多少次,返回都是true
  5. 任何情况下,x.equals(null),永远返回是false,x.equals(与x是不同类型的对象),也永远返回是false。

对于上面几个规则,我们在使用的过程中最好遵守,避免出现意想不到的错误。

4、小结

1、==比较的数值是否相等和对象地址是否相等。

2、equals()方法比较的对象内容是否相等(前提是重写了父类的方法)。

3、一般除了自定义的类除外,大部分能够使用的类都重写了equals()方法。

夯实Java基础(五)——==与equals()的更多相关文章

  1. 夯实Java基础系列目录

    自进入大学以来,学习的编程语言从最初的C语言.C++,到后来的Java,. NET.而在学习编程语言的同时也逐渐决定了以后自己要学习的是哪一门语言(Java).到现在为止,学习Java语言也有很长一段 ...

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

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

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

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

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

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

  5. 夯实Java基础系列9:深入理解Class类和Object类

    目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); register ...

  6. 夯实Java基础系列13:深入理解Java中的泛型

    目录 泛型概述 一个栗子 特性 泛型的使用方式 泛型类 泛型接口 泛型通配符 泛型方法 泛型方法的基本用法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型方法总结 泛型上下边界 泛型常见面试 ...

  7. 夯实Java基础系列14:深入理解Java枚举类

    目录 初探枚举类 枚举类-语法 枚举类的具体使用 使用枚举类的注意事项 枚举类的实现原理 枚举类实战 实战一无参 实战二有一参 实战三有两参 枚举类总结 枚举 API 总结 参考文章 微信公众号 Ja ...

  8. 夯实Java基础(十一)——内部类

    1.内部类的概念 内部类顾名思义:将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.对于很多Java初学者来说,内部类学起来真的是一头雾水,根本理解不清楚是个什么东西,包括我自己(我太菜 ...

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

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

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

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

随机推荐

  1. leadcode的Hot100系列--64. 最小路径和--权值最小的动态规划

    如果这个: leadcode的Hot100系列--62. 不同路径--简单的动态规划 看懂的话,那这题基本上是一样的, 不同点在于: 1.这里每条路径相当于多了一个权值 2.结论不再固定,而是要比较不 ...

  2. Python之Pandas库学习(二):数据读写

    1. I/O API工具 读取函数 写入函数 read_csv to_csv read_excel to_excel read_hdf to_hdf read_sql to_sql read_json ...

  3. SPOJ INTSUB - Interesting Subset(数学)

    http://www.spoj.com/problems/INTSUB/en/ 题意:给定一个集合,该集合由1,2,3....2n组成,n是一个整数.问该集合中有趣子集的数目,答案mod1e9+7. ...

  4. 超哥的 LINUX 入门大纲

    前言 “Linux?听说是一个操作系统,好用吗?” “我也不知道呀,和windows有什么区别?我能在Linux上玩LOL吗” “别提了,我用过Linux,就是黑乎乎一个屏幕,鼠标也不能用,不停地的敲 ...

  5. vue中ajax应用

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. EnjoyingSoft之Mule ESB开发教程系列第五篇:控制消息的流向-数据路由

    目录 1. 使用场景 2. 基于消息头的路由 2.1 使用JSON提交订单的消息 2.2 使用XML提交订单的消息 2.3 使用Choice组件判断订单格式 3. 基于消息内容的路由 4. 其他控制流 ...

  7. 后端开发工具:反编译工具、VS插件、.NET Framework源码地址

    再学习.工作中,开发免不了要使用第三方工具.今天介绍2款反编译工具 一.dnspy 免安装.免费.可调试.可修改重新编译dll 开源项目地址:https://github.com/0xd4d/dnSp ...

  8. Hadoop FAQ

    测试环境: Hadoop 2.6.0-cdh5.7.1 apache-kylin-2.0.0-bin kylin运行check-env.sh时,报如下警告: WARN util.NativeCodeL ...

  9. [记录]Python的master-worker和epoll模式

    #master-worker模型: #coding:utf-8 import os import sys import socket import time import traceback impo ...

  10. 根据数据库帮助类采用事务插入图片到sql server数据库中

    我们定义数据库为image类型,然后读取图片为字符流,再保存到数据库中,首先我们定义一个读取图片的公共类,此公共类以后会用到,所以可以建立相应的帮助类 public static byte[] Rea ...