Java中equals()方法实例详解

目录
  • equals()在哪里
  • Java中重写的equals()
  • 在Java中比较的推荐方法
  • 为什么要在我们自己的类中重写equals()
  • 重写equals()的规范
  • 重写equals()可能的误区
  • 一般的equals()写法
  • 附:java中equals()方法的正确使用
  • 总结

equals()在哪里

首先我们知道Java中Object类是所有类的父类,它里面定义了equals()方法:

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

可以看到是使用= =来进行比较的,那么= =是什么意思呢?其实是比较两个对象的的内存地址。(这里顺便提一下,可以去了解一下Java的堆栈。)

=》若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。

Java中重写的equals()

这里我们看一下java的一些自带的包装类怎么重写equals()的:

String.java

    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;
    }

我们可以非常清晰的看到String的equals()方法是进行内容比较,而不是单纯的引用比较。

Integer.java

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

其他的就不一一举例了。

在Java中比较的推荐方法

所以我们一般比较基本数据类型的时候,使用"==",例如 int i = 0; if (i == 1){…},比较两个Integer包装类类型的时候就可以使用equals(),因为Java已经重写了equals()方法了。另外给出几点建议,在java中进行比较,我们需要根据比较的类型来选择合适的比较方式:

  1. 对象域,使用equals方法 。
  2. 类型安全的枚举,使用equals或== 。
  3. 可能为null的对象域 : 使用==null 和 equals 。
  4. 数组域 : 使用 Arrays.equals 。
  5. 除float和double外的原始数据类型(int,byte等) : 使用 == 。
  6. float类型: 使用Float.foatToIntBits转换成int类型,然后使用==。
  7. double类型: 使用Double.doubleToLongBit转换成long类型,然后使用==。

其中6,7参考java中的对应的包装类实现:

public boolean equals(Object obj) {
    return (obj instanceof Float)
           && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
    }
}

为什么要在我们自己的类中重写equals()

但是有时候我们不满足于使用基本数据类型和Java实现的一些继承自Object的哪些类,比如我们实现一个Person类,它是继承自Object类的,所以它的equals()方法默认使用的是文章开头提到的哪个equals()方法,当我们使用equals()进行比较的时候,比较内存地址,那么有可能出现两个Person对象的参数都相同(比如年龄,身份证号等,在我们的实际认知中认为这两个人就是一个人,应该返回true),但是由于他们的内存地址是不一样的,所以equals()方法会返回false。

那么我们就需要去重写equals()方法。

重写equals()的规范

需要注意的是,在Java规范中,它对equals()方法的使用必须要遵循如下几个规则:

  1. 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
  2. 对称性:对于任何非空引用值 x 和 y,当且仅当y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
  3. 传递性:对于任何非空引用值 x、y 和z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
  4. 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回4、一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回false,前提是对象上 equals 比较中所用的信息没有被修改
  5. 对于任何非空引用值 x,x.equals(null) 都应返回false。

重写equals()可能的误区

查看下述代码:

public class TestEquals {
    public static void main(String[] args) {
        Employee employee = new Employee("mily",1);
        Employee employee2 = new Employee("mily",2);
        Person p1 = new Person("mily");

        System.out.println(p1.equals(employee));
        System.out.println(p1.equals(employee2));
        System.out.println(employee.equals(employee2));
    }
}

class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    @Override
    public boolean equals(Object obj) {

        if (obj instanceof Person) {
            Person person = (Person) obj;
            if (person.getName() == null | name == null) {
                return false;
            } else {
                return name.equalsIgnoreCase(person.getName());
            }
        }

        return false;
    }
}

class Employee extends Person {

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Employee(String name, int id) {
        super(name);
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {

        if (obj instanceof Employee) {
            Employee employee = (Employee) obj;
            return super.equals(obj) && employee.getId() == id;
        }

        return false;
    }
}

输出:

true

true

false

上述代码中,我定义了一个Person类,有一个属性name;还定义了一个Employee类,它是Person的子类,多出一个id的属性;在测试代码中“new”出了三个对象:

  1. name为mily,id为1的一个职员 —— employee
  2. name为mily,id为2的职员 —— employee2
  3. name为mily的一个普通人 —— p1

在大家的认知下,应该是三者都不是“equal”的,但是在执行 p1.equals(employee)时返回的是true,仔细看了代码之后你就会发现问题所在,代码把employee当成一个Person对象去执行equals方法了,比较了name发现一样,就认为是“equal”了,这是一种很常见的误区。

一般的equals()写法

下面给出一个完美的 equals 方法的建议:

1、显示参数命名为 otherObject,稍后会将它转换成另一个叫做 other 的变量。

2、判断比较的两个对象引用是否相等,如果引用相等那么表示是同一个对象,那么当然相等

3、如果 otherObject 为 null,直接返回false,表示不相等

4、比较 this 和 otherObject 是否是同一个类:如果 equals 的语义在每个子类中有所改变,就使用 getClass 检测;如果所有的子类都有统一的定义,那么使用 instanceof 检测

5、将 otherObject 转换成对应的类类型变量

6、最后对对象的属性进行比较。使用 == 比较基本类型,使用 equals 比较对象。如果都相等则返回true,否则返回false。注意如果是在子类中定义equals,则要包含 super.equals(other)

按照上述的equals()规范,我的实现如下:

public class TestEquals2 {
    public static void main(String[] args) {
        Employee employee = new Employee("mily",1);
        Employee employee2 = new Employee("mily",1);
        Person p1 = new Person("mily");

        System.out.println(p1.equals(employee));
        System.out.println(p1.equals(employee2));
        System.out.println(employee.equals(employee2));

        Employee employee3 = new Employee(null,1);
        Employee employee4 = new Employee(null,1);
        Person p2 = new Person(null);
        System.out.println(p2.equals(employee3));
        System.out.println(p2.equals(employee4));
        System.out.println(employee3.equals(employee4));
    }
}

class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }

        if(obj == null || getClass() != obj.getClass()){
            return false;
        }

        Person person = (Person) obj;
        if(person.getName() == null | name == null) {
            return false;
        } else {
            return name.equalsIgnoreCase(person.getName());
        }

    }
}

class Employee extends Person {

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Employee(String name, int id) {
        super(name);
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }

        if(obj == null || getClass() != obj.getClass()){
            return false;
        }

        Employee employee = (Employee) obj;
        if(employee.getName() == null | getName() == null) {
            return false;
        }else {
            return getName().equalsIgnoreCase(employee.getName()) && employee.getId() == id;
        }

    }
}

结果:

false

false

true

false

false

false

附:java中equals()方法的正确使用

在Java中比较两个字符串是否相等,想必只要不是初学者都知道用equals()方法来进行比较,但是实际上很多时候都用错了。

就我自己开发而言,加入比较一个String s的内容是否是"aaa"时,往往会写成如下代码:

if(s.equals("aaa")){
    ...
}

乍一看没什么问题,直到我装了Alibaba Coding Guidelines 这个插件,一检查,就告诉我这样不对了。

为什么呢?因为很多情况下,并不能保证字符串s是不是为null,即直接这么判断,很容易产生空指针异常的错误,因此正确的使用方法应该是:

"aaa".equals(s);

总结

到此这篇关于Java中equals()方法的文章就介绍到这了,更多相关Java equals()方法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中判断对象是否相等的equals()方法使用教程

    Object类中的equals方法用于检测一个对象是否等于另一个对象.在Object类中,这个方法判断两个对象是否具有相同的引用,如果两个对象具有相同的引用,它们一定是相等的.从这点上看,将其作为默认操作也是合乎情理的.然而,对于多数类类说,这种判断并没有什么意义,例如,采用这种方式比较两个PrintStream是否相等就完全没有意义.然而,经常需要检测两个对象状态的相等性,如果两个对象的状态相等,就认为这两个对象是相等的.所以一般在自定义类中都要重写equals比较. 下面给出编写一个完美eq

  • java中的equals()和toString()方法实例详解

    java中的equals()和toString()方法 , 这里写个小例子帮助大家学习理解此部分知识. /* 所有对象的父类Object Object中的方法: equals() 对象是否相同的比较方法 toString()对象的字符串表现形式 */ class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } } class ObjectDemo {

  • Java中equals()方法重写实现代码

    Java中equals()方法重写实现代码 Java中的equals()方法是在Object类中定义,Object类是所有类的父类.换句话说,任何类都隐含地继承了该方法.判断两个对象的内容是否相同,必须使用equals()方法,对于没有重写该方法的类,需要重写该方法. 重写equals()方法代码如下: /** *equlas()方法重写实例 */ class User { /** *方法描述:设置name值 *输入参数:String name *返回类型:void */ public void

  • Java equals()方法使用详解及总结

    equals()    超类Object中有这个equals()方法,该方法主要用于比较两个对象是否相等.该方法的源码如下: public boolean equals(Object obj) { return (this == obj); } 我们知道所有的对象都拥有标识(内存地址)和状态(数据),同时"=="比较两个对象的的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等,即若object1.equals(object2)为true,则表示eq

  • Java中的== 和equals()方法详解与实例

    Java中的== 和equals()方法: Java中的数据类型,可分为两类: 1.基本数据类型,也称原始数据类型. byte,short,char,int,long,float,double,boolean,他们之间的比较,应用双等号(==),比较的是他们的值. 2.引用数据类型(类) 当它们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false. Java当中所有的类都是继承于Object这个基类

  • Java中equals()方法实例详解

    目录 equals()在哪里 Java中重写的equals() 在Java中比较的推荐方法 为什么要在我们自己的类中重写equals() 重写equals()的规范 重写equals()可能的误区 一般的equals()写法 附:java中equals()方法的正确使用 总结 equals()在哪里 首先我们知道Java中Object类是所有类的父类,它里面定义了equals()方法: public boolean equals(Object obj) { return (this == obj

  • java 中匿名内部类的实例详解

    java 中匿名内部类的实例详解 原来的面貌: class TT extends Test{ void show() { System.out.println(s+"~~~哈哈"); System.out.println("超级女声"); } TT tt=new TT(); tt.show(); 只是说我们这里采用的是匿名的形式来处理. 重写了Test的show()方法,在重写好了以后,又调用了重写后的show()方法 实现代码: package cn.com; c

  • Java中File的实例详解

    Java中File的实例详解 File 代表文件或者目录的类 构造函数 File(File parent,String child)---代表了指定父目录下的指定的子文件或者子目录 File(String pathname)---代表了指定路径对应的文件或者目录对象 重要方法 创建 createNewFile()---只能用来创建文件,并且一次只能创建一个文件,要求文件存储的目录必须真实存在 mkdir()---只能用来创建目录,不能用来创建多层目录 mkdirs()---创建多层目录 删除 d

  • java金钱处理方法实例详解

    java金钱处理方法实例详解 在支付行业中,涉及到对金钱的处理比较多.比如分转化成元.费率计算.手续费计算等等. 1.分转化成元 /** * 单位换算:分->元 * * @param amount * 分 * @param scale * 保留小数点位数 * @return */ public static String fenToYuan(long amount, int scale) { return new BigDecimal(amount).divide(new BigDecimal(

  • Java身份证验证方法实例详解

    Java身份证验证方法实例详解 身份证号码验证 1.号码的结构 公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成.排列顺序从左至右依次为:六位数字地址码, 八位数字出生日期码,三位数字顺序码和一位数字校验码. 2.地址码(前六位数) 表示编码对象常住户口所在县(市.旗.区)的行政区划代码,按GB/T2260的规定执行. 3.出生日期码(第七位至十四位) 表示编码对象出生的年.月.日,按GB/T7408的规定执行,年.月.日代码之间不用分隔符. 4.顺序码(第十五位至十七位) 表示在同

  • 浅谈JAVA中输入输出流实例详解

    java语言的输入输出功能是十分强大而灵活的,美中不足的是看上去输入输出的代码并不是很简洁,因为你往往需要包装许多不同的对象.在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流....本文的目的是为大家介绍JAVA中输入输出流实例详解. 流的层次结构 定义:        java将读取数据对象成为输入流,能向其写入的对象叫输出流.结构图如下: 1.输入输出: 输入/输出(Input/Output)是指对某

  • java 中内部类的实例详解

    java 中内部类的实例详解 一:内部类可直接访问外部类的成员变量,包括外部类私有的成员变量 二:外部类要访问内部类的成员变量,需要建立内部类的对象 class Outer{ int x=110; public void show(){ System.out.println("外部类的x="+x); } public void showInner(){ Inner inner=new Inner(); inner.show(); System.out.println(inner.x);

  • java 中List删除实例详解

    java 中List删除实例详解 1.循环删除List中的元素 public static void main(String[] args) { List<String> t=new ArrayList<String>(); for (int i = 0; i < 10; i++) { t.add(""+i+""); } System.out.println("原有的List:"+t.toString()); for

  • MongoDB中aggregate()方法实例详解

    目录 前言 1,了解aggergate()方法 2,实现聚合表达式运算符 总结 前言 MongoDB的一个很大的好处是能够使用MapReduce来吧数据库查询的结果简化成一个与原来的集合完全不同的结构.MapReduce把一个数据库查询的值映射为一个完全不同的形式,然后简化结果,使它们的可用性更好. MongoDB有一个MapReduce框架,它也允许你使用聚合来简化吧一个MapReduce操作传输到另一个MapReduce操作的一系列过程.有了MapReduce和聚合,可以用数据生成一些不平凡

  • Java中泛型使用实例详解

    Java中泛型使用 泛型作用: 泛型:集合类添加对象不用强转 反射机制:将泛型固定的类的所有方法和成员全部显示出来 核心代码: ArrayList<Ls> ff=new ArrayList()<Ls>; Ls ls1=new Ls("薯片",5f); ff.add(ls1); Ls cls=ff.get(0);//这里不再需要强转 代码实例: 说明:这是非泛型的代码,集合类中调用对象时需要强转 import java.util.*; public class L

随机推荐