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

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

下面给出编写一个完美equals()方法的建议:

(1)显式参数命名为otherObject,稍后需要将转换成一个叫other的变量

(2)检测this与otherObject是否引用同一个对象:

if(this==otherObject) return true;

这条语句只是一个优化。实际上,这是一种经常采用的形式。因为计算这个等式要比一个一个地比较类中的域所付出的代价小的多。

(3)检测otherObject是否为null,如果为null,返回false。这项检测是很必要的。

if(otherObject==null) return false;

(4)比较this和otherObject是否属于同一个类,如果equals的语义在每个子类中有所改变,就使用getClass()检测,它将自己作为目标类

if(getClass()!=otherObject.getClass()) return false;

如果所有的子类都拥有同一的语义,就使用instanceof检测

if(!(otherObject instanceof ClassName)) return false;

(5)将otherObject转换为相应类型的变量:

ClassName other=(ClassName)otherObject;

(6)现在开始对所有需要比较的域进行比较。使用==比较基本类型域,使用equals比较对象域。如果所有域都匹配,就返回true,否则返回false;

return field1==other.field1&&field2.equals(other.field2)

如果在子类中重新定义equals,就要在其中包含调用super.equals(other)。如果检测失败,就不可能相等。如果超类中的域相等,就比较子类中的实例域。

对于数组类型的域,可以使用静态的Arrays.equals方法检测相应的元素是否相等。

来看几个字符串比较例子:

String a = "abc";
String b = "abc";
String c = new String("abc");
String d = new String("abc");
System.out.println(a == b); // true 因为JAVA中字符串常量是共享的,只有一个拷贝
System.out.println(a == c); // false a和c属于2个不同的对象
System.out.println(a.equals(c)); // true 由于String对象的equals方法比较的是对象中的值,所以返回true。(和Object的equals方法不同)
System.out.println(c==d); // false c和d虽然对象内的值相同,但属于2个不同的对象,所以不相等
System.out.println(c.equals(d)); // true

简单的说,当比较字符串常量时,等于和equals返回的结果一样,当想比较字符串对象的值时用equals。

看一个equals的使用例子:

package chapter05.EqualsTest; 

import java.util.*; 

public class EqualsTest {
 public static void main(String[] args) {
  Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
  Employee alice2 = alice1; // reference the same object
  Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
  Employee bob = new Employee("Bob Brandson", 50000, 1989, 10, 1); 

  System.out.println("alice1 == alice2: " + (alice1 == alice2)); 

  System.out.println("alice1 == alice3: " + (alice1 == alice3)); 

  System.out.println("alice1.equals(alice3): " + (alice1.equals(alice3))); 

  System.out.println("alice1.equals(bob): " + (alice1.equals(bob))); 

  System.out.println(bob.toString());
 }
} 

class Employee {
 public Employee(String n, double s, int year, int month, int day) {
  name = n;
  salary = s;
  GregorianCalendar calendar = new GregorianCalendar(year, month, day);
  hireDay = calendar.getTime();
 } 

 public String getName() {
  return name;
 } 

 public double getSalary() {
  return salary;
 } 

 public Date getHireDay() {
  return hireDay;
 } 

 public void raiseSalary(double byPercent) {
  double raise = salary * byPercent / 100;
  salary += raise;
 } 

 @Override
 public boolean equals(Object otherObject) {
  // a quick test to see if the objects are identical
  if (this == otherObject)
   return true; 

  // must return false if the explicit parameter is null
  if (otherObject == null)
   return false; 

  // if the classed don't match,they can't be equal
  if (getClass() != otherObject.getClass())
   return false; 

  // now we know otherObject is a non-null Employee
  Employee other = (Employee) otherObject; 

  // test whether the fields hava identical values
  return name.equals(other.name) && salary == other.salary
    && hireDay.equals(other.hireDay); 

 } 

 @Override
 public int hashCode() {
  return 7 * name.hashCode() + 11 * new Double(salary).hashCode() + 13
    * hireDay.hashCode();
 } 

 @Override
 public String toString() {
  return getClass().getName() + "[name=" + name + ",salary=" + salary
    + ",hireDay=" + hireDay + "]";
 } 

 private String name;
 private double salary;
 private Date hireDay;
} 

class Manager extends Employee {
 public Manager(String n, double s, int year, int month, int day) {
  super(n, s, year, month, day);
  bouns = 0;
 } 

 @Override
 public double getSalary() {
  double baseSalary = super.getSalary();
  return baseSalary + bouns;
 } 

 public void setBouns(double b) {
  bouns = b;
 } 

 @Override
 public boolean equals(Object otherObject) {
  if (!super.equals(otherObject))
   return false;
  Manager other = (Manager) otherObject;
  // super equals checked that this and other belong to the same class
  return bouns == other.bouns;
 } 

 @Override
 public int hashCode() {
  return super.hashCode() + 17 * new Double(bouns).hashCode();
 } 

 @Override
 public String toString() {
  return super.toString() + "[bouns=" + bouns + "]";
 } 

 private double bouns;
}

深入
下面根据“类是否覆盖equals()方法”,将它分为2类。
(1) 若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象。
(2) 我们可以覆盖类的equals()方法,来让equals()通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。
下面,举例对上面的2种情况进行说明。
1. “没有覆盖equals()方法”的情况
代码如下 (EqualsTest1.java):

import java.util.*;
import java.lang.Comparable;

/**
 * @desc equals()的测试程序。

 */
public class EqualsTest1{

 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("%s\n", p1.equals(p2));
 }

 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;

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

  public String toString() {
   return name + " - " +age;
  }
 }
}

运行结果:

代码如下:

false

结果分析
我们通过 p1.equals(p2) 来“比较p1和p2是否相等时”。实际上,调用的Object.java的equals()方法,即调用的 (p1==p2) 。它是比较“p1和p2是否是同一个对象”。
而由 p1 和 p2 的定义可知,它们虽然内容相同;但它们是两个不同的对象!因此,返回结果是false。

2. "覆盖equals()方法"的情况
我们修改上面的EqualsTest1.java:覆盖equals()方法。
代码如下 (EqualsTest2.java):

import java.util.*;
import java.lang.Comparable;

/**
 * @desc equals()的测试程序。
 */
public class EqualsTest2{

 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("%s\n", p1.equals(p2));
 }

 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;

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

  public String toString() {
   return name + " - " +age;
  }

  /**
   * @desc 覆盖equals方法
   */
  @Override
  public boolean equals(Object obj){
   if(obj == null){
    return false;
   } 

   //如果是同一个对象返回true,反之返回false
   if(this == obj){
    return true;
   } 

   //判断是否类型相同
   if(this.getClass() != obj.getClass()){
    return false;
   } 

   Person person = (Person)obj;
   return name.equals(person.name) && age==person.age;
  }
 }
}

运行结果:

代码如下:

true

结果分析:
我们在EqualsTest2.java 中重写了Person的equals()函数:当两个Person对象的 name 和 age 都相等,则返回true。
因此,运行结果返回true。
讲到这里,顺便说一下java对equals()的要求。有以下几点:
对称性:如果x.equals(y)返回是"true",那么y.equals(x)也应该返回是"true"。
反射性:x.equals(x)必须返回是"true"。
类推性:如果x.equals(y)返回是"true",而且y.equals(z)返回是"true",那么z.equals(x)也应该返回是"true"。
一致性:如果x.equals(y)返回是"true",只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是"true"。
非空性,x.equals(null),永远返回是"false";x.equals(和x不同类型的对象)永远返回是"false"。
现在,再回顾一下equals()的作用:判断两个对象是否相等。当我们重写equals()的时候,可千万不好将它的作用给改变了!

equals() 与 == 的区别是什么?
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况(前面第1部分已详细介绍过):
     情况1,类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
     情况2,类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
下面,通过示例比较它们的区别。
代码如下:

import java.util.*;
import java.lang.Comparable;

/**
 * @desc equals()的测试程序。
 */
public class EqualsTest3{

 public static void main(String[] args) {
  // 新建2个相同内容的Person对象,
  // 再用equals比较它们是否相等
  Person p1 = new Person("eee", 100);
  Person p2 = new Person("eee", 100);
  System.out.printf("p1.equals(p2) : %s\n", p1.equals(p2));
  System.out.printf("p1==p2 : %s\n", p1==p2);
 }

 /**
  * @desc Person类。
  */
 private static class Person {
  int age;
  String name;

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

  public String toString() {
   return name + " - " +age;
  }

  /**
   * @desc 覆盖equals方法
   */
  @Override
  public boolean equals(Object obj){
   if(obj == null){
    return false;
   } 

   //如果是同一个对象返回true,反之返回false
   if(this == obj){
    return true;
   } 

   //判断是否类型相同
   if(this.getClass() != obj.getClass()){
    return false;
   } 

   Person person = (Person)obj;
   return name.equals(person.name) && age==person.age;
  }
 }
}

运行结果:

p1.equals(p2) : true
p1==p2 : false

结果分析:
在EqualsTest3.java 中:
(1) p1.equals(p2)
这是判断p1和p2的内容是否相等。因为Person覆盖equals()方法,而这个equals()是用来判断p1和p2的内容是否相等,恰恰p1和p2的内容又相等;因此,返回true。
(2) p1==p2
这是判断p1和p2是否是同一个对象。由于它们是各自新建的两个Person对象;因此,返回false。

(0)

相关推荐

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

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

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

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

  • 详解Java中“==”与equals()的区别

    Java中"=="与equals()的区别 对于关系操作符"==",<Java编程思想>中是这样描述的:"关系操作符生成的是一个boolean结果,它们计算的是操作数的值之间的关系".这里的操作数的"值"值得我们注意.对于8种基本数据类型(boolean,byte,char,short,int,float,double,long),它们的变量直接存储的就是"值".所以,我们用"==&q

  • 探索Java中的equals()和hashCode()方法_动力节点Java学院整理

    equals()和hashCode()区别?  equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值.  hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数.根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的:当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了. 之所以有hashCode方法,是因为在批量的对象比

  • 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()方法使用详解及总结

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

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

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

  • Java中判断对象是否为空的方法的详解

    首先来看一下工具StringUtils的判断方法: 一种是org.apache.commons.lang3包下的: 另一种是org.springframework.util包下的.这两种StringUtils工具类判断对象是否为空是有差距的: StringUtils.isEmpty(CharSequence cs); //org.apache.commons.lang3包下的StringUtils类,判断是否为空的方法参数是字符序列类,也就是String类型 StringUtils.isEmpt

  • JavaScript中判断对象类型的几种方法总结

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一个说明运算数类型的字符串.如:"number","string","boolean","object","function","undefined"(可用于判断变量是否存在). 但 type

  • 浅谈java中的对象、类、与方法的重载

    对象: 一切皆为对象. 对象包括两部分内容:属性(名词形容词),行为(动词). 对象和对象之间是有关系的: 派生,关联,依赖. 类: 对同一类别的众多对象的一种抽象. 类,还是用来生成对象的一种模板,对象是类的一种具体化的表现. 面向对象的三大特性:封装,继承,多态. class 类名{ 访问修饰符 成员变量的定义; 访问修饰符 成员函数(方法)的定义; } 访问修改符:默认不写,private,public. private,私有.只能被当前class 类名{}中的代码访问到.出了这个类的{}

  • Java中判断字符串是否相等的实现

    在最近的开发中,我踩到一个坑,过程是这样的.我需要在Java中判断两个字符串是否相等,按照以往的经历使用 == 双等号的操作符来判断,但是在Java中,这样写却没有实现我想要的效果.经过查阅资料后,把得到的经验分享给大家. 相等判断操作符== Java中,==相等判断符用于判断基本数据类型和引用数据类型. 当判断基本数据类型的时候判断的是数值,当判断引用数据类型时判断变量是否指向同一引用对象. 使用==判断字符串时,判断的是两个字符串是否指向同一个对象.如果两个字符串指向同一个对象,那么它们就是

  • 如何在Java中判断两个Long类型是否相等

    目录 一.为什么同样的类型,同样的值,却不相等呢? 1.探索一下源码 二.解决方案 1.可以使用.longValue() 2.equals()进行比较 三.例子 一.为什么同样的类型,同样的值,却不相等呢? 1.探索一下源码 源码中显示,Long中有一个静态的内部类LongCache,专门用于缓存-128至127之间的值,一共256个元素. 如果值在[-128, 127]之间,会放在缓存里面,而超过这个范围就要new一个新的对象,也就是说==不能判断对象是否相等.当然,如果值是在[-128, 1

  • java中response对象用法实例分析

    本文实例讲述了java中response对象用法.分享给大家供大家参考,具体如下: <jsp:forward>动作元素用于运行时在服务器端结束当前页面的执行,并从当前页面转向指定页面. 使用response对象的setHeader()方法可以设置页面的自动刷新时间间隔.实现每隔60秒重新加载本页面的语句为: 复制代码 代码如下: response.setHeader("refresh",60); 而实现3秒后浏览器加载新页面http://www.jb51.net的语句为:

  • java中List对象排序通用方法

    本文实例讲述了java中List对象排序通用方法.分享给大家供大家参考.具体分析如下: 在数据库中查出来的列表list中,往往需要对不同的字段重新排序,一般的做法都是使用排序的字段,重新到数据库中查询.如果不到数据库查询,直接在第一次查出来的list中排序,无疑会提高系统的性能. 只要把第一次查出来的结果存放在session中,就可以对list重新排序了.一般对list排序可以使用Collections.sort(list),但如果list中包含是一个对象的话,这种方法还是行不通的.那要怎么排序

  • java中同类对象之间的compareTo()和compare()方法对比分析

    首先我们都知道java中的比较都是同一类对象与对象之间的比较,就好像现实生活中比较人和人的年龄一样,你不会去把人的年龄和人的身高来比较,这显然是没有意义的. java中同类对象之间的比较又分为两种,基本类型之间的比较和引用类型之间的比较. java中"=="比较对象是否引用了同一个对象,或者比较基本类型变量值是否相等.Object类的equals()方法用来比较是否一个对象(内存地址比较),可以重写. JDK中有些类重写了equals()方法,只要类型.内容都相同,就认为相等.很变态的

  • 在js与java中判断json数据中是否含有某字段的案例

    js中 从服务端传过来一个json数据为data 1.data["key"] != undefined //这种有缺陷,如果这个key定义了,并且就是很2的赋值为undefined,那么这句就会出问题了 2.!("data" in obj) 3.data.hasOwnProperty("key") //后面两种推荐使用 java程序中判断是否存在 data 为从浏览器传回来的json数据 当读取数据的时候最好先加一个判断,不然如果里面不含有该数据

随机推荐