如何在Java中重写equals方法

如何在Java中重写equals方法,java,overriding,equals,Java,Overriding,Equals,我试图重写Java中的equals方法。我有一个类People,它基本上有两个数据字段name和age。现在我想重写equals方法,这样我就可以在两个人对象之间进行检查 我的代码如下 public boolean equals(People other){ boolean result; if((other == null) || (getClass() != other.getClass())){ result = false; } // end if

我试图重写Java中的equals方法。我有一个类
People
,它基本上有两个数据字段
name
age
。现在我想重写
equals
方法,这样我就可以在两个人对象之间进行检查

我的代码如下

public boolean equals(People other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(other.name) &&  age.equals(other.age);
    } // end else

    return result;
} // end equals

但当我写
age.equals(other.age)
时,它会给我错误,因为equals方法只能比较字符串,而age是整数

解决方案
我按照建议使用了
==
运算符,我的问题就解决了。

因为我猜
年龄
属于
int
类型:

public boolean equals(Object other){
    boolean result;
    if((other == null) || (getClass() != other.getClass())){
        result = false;
    } // end if
    else{
        People otherPeople = (People)other;
        result = name.equals(otherPeople.name) &&  age == otherPeople.age;
    } // end else

    return result;
} // end equals

我不确定细节,因为您尚未发布全部代码,但是:

  • 记住也要覆盖
    hashCode()
  • equals
    方法的参数类型应该是
    Object
    ,而不是
    People
    。目前,您正在重载而不是重写equals方法,这可能不是您想要的,特别是考虑到您稍后会检查它的类型
  • 您可以使用
    instanceof
    检查它是否为人员对象,例如
    如果(!(其他人员实例)){result=false;}
  • equals
    用于所有对象,但不用于基本体。我想你的意思是年龄是一个
    int
    (原语),在这种情况下只需使用
    =
    。请注意,整数(大写“I”)是一个对象,应该与equals进行比较

有关详细信息,请参阅。

如果年龄为int,则应使用==如果它是Integer对象,则可以使用equals()。
如果重写equals,还需要实现hashcode方法。合同的详细信息可以在对象的javadoc中找到,也可以在web的各个页面上找到。

引入一个新的方法签名来更改参数类型,称为重载:

公共布尔等于(其他人){
这里的
对象
不同

// Class with a typical equals method

public final class PhoneNumber {

    private final short areaCode, prefix, lineNum;

    public PhoneNumber(int areaCode, int prefix, int lineNum) {

        this.areaCode = rangeCheck(areaCode,  999, "area code");

        this.prefix   = rangeCheck(prefix,    999, "prefix");

        this.lineNum  = rangeCheck(lineNum,  9999, "line num");

    }

    private static short rangeCheck(int val, int max, String arg) {

        if (val < 0 || val > max)

           throw new IllegalArgumentException(arg + ": " + val);

        return (short) val;

    }

    @Override public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof PhoneNumber))
            return false;
        PhoneNumber pn = (PhoneNumber)o;
        return pn.lineNum == lineNum && pn.prefix == prefix
                && pn.areaCode == areaCode;
    }
    ... // Remainder omitted

}
当一个方法签名与其超类的签名保持一致时,它被称为重写,而
@Override
注释有助于在编译时区分这两种签名:

@覆盖
公共布尔等于(对象其他){
如果看不到年龄的实际声明,就很难说出现错误的原因。

//作者K@stackoverflow
//Written by K@stackoverflow
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        ArrayList<Person> people = new ArrayList<Person>();
        people.add(new Person("Subash Adhikari", 28));
        people.add(new Person("K", 28));
        people.add(new Person("StackOverflow", 4));
        people.add(new Person("Subash Adhikari", 28));

        for (int i = 0; i < people.size() - 1; i++) {
            for (int y = i + 1; y <= people.size() - 1; y++) {
                boolean check = people.get(i).equals(people.get(y));

                System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
                System.out.println(check);
            }
        }
    }
}

//written by K@stackoverflow
public 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 obj) {
        if (obj == null) {
            return false;
        }

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

        final Person other = (Person) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }

        if (this.age != other.age) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
        hash = 53 * hash + this.age;
        return hash;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
公共班机{ /** *@param指定命令行参数 */ 公共静态void main(字符串[]args){ //此处的TODO代码应用程序逻辑 ArrayList people=新建ArrayList(); 添加(新人物(“Subash Adhikari”,28)); 添加(新人员(“K”,28)); 添加(新人员(“StackOverflow”,4)); 添加(新人物(“Subash Adhikari”,28)); 对于(inti=0;i对于(int y=i+1;y在Java中比较对象时,进行语义检查,将对象的类型和标识状态与以下对象进行比较:

  • 自身(同一实例)
  • 自身(克隆或重建副本)
  • 其他不同类型的对象
  • 相同类型的其他对象
  • null
规则:

  • 对称性:
    a.equals(b)==b.equals(a)
  • equals()
    始终产生
    true
    false
    ,但决不会产生
    NullpointerException
    ClassCastException
    或任何其他可丢弃的异常
比较:

  • 类型检查:两个实例都必须是相同的类型,这意味着您必须比较实际的类是否相等。当开发人员使用
    instanceof
    进行类型比较时,这通常无法正确实现(它只在没有子类的情况下工作,并且在
    A扩展B->A instanceof B!=B instanceof A时违反对称规则)
  • 识别状态的语义检查:确保您了解实例的识别状态。可以通过其社会保险号识别人员,但不能通过头发颜色(可染色)、姓名(可更改)或年龄(随时更改)进行识别。只有通过值对象才能比较完整状态(所有非瞬态字段),否则仅检查标识实例的内容
对于您的
人员
班级:

public boolean equals(Object obj) {

    // same instance
    if (obj == this) {
        return true;
    }
    // null
    if (obj == null) {
        return false;
    }
    // type
    if (!getClass().equals(obj.getClass())) {
        return false;
    }
    // cast and compare state
    Person other = (Person) obj;
    return Objects.equals(name, other.name) && Objects.equals(age, other.age);
}
可重用的通用实用程序类:

public final class Equals {

    private Equals() {
        // private constructor, no instances allowed
    }

    /**
     * Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state
     *
     * @param instance       object instance (where the equals() is implemented)
     * @param other          other instance to compare to
     * @param stateAccessors stateAccessors for state to compare, optional
     * @param <T>            instance type
     * @return true when equals, false otherwise
     */
    public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) {
        if (instance == null) {
            return other == null;
        }
        if (instance == other) {
            return true;
        }
        if (other == null) {
            return false;
        }
        if (!instance.getClass().equals(other.getClass())) {
            return false;
        }
        if (stateAccessors == null) {
            return true;
        }
        return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other)));
    }
}
public boolean equals(Object obj) {
    return Equals.as(this, obj, t -> t.name, t -> t.age);
}
第10项:当压倒一切时,遵守总合同 ,重写
equals
方法似乎很简单,但有很多方法会出错,并且后果可能很严重。避免问题的最简单方法不是重写
equals
方法,在这种情况下,类的每个实例都只与自身相等。如果出现以下任何一种情况,那么这样做是正确的:pply:

  • 类的每个实例本身都是唯一的。对于表示活动实体而不是值的类(如线程),这一点是正确的。对象提供的equals实现对这些类具有完全正确的行为

  • 类不需要提供“逻辑等式”test.例如,java.util.regex.Pattern可以重写equals以检查两个模式实例是否表示完全相同的正则表达式,但设计者认为客户端不需要或不需要此功能。在这种情况下,从对象继承的equals实现是理想的

  • 一个超类已经重写了equals,并且超类行为适合于该类。例如,大多数集合实现从AbstractSet继承equals实现,从AbstractList继承List实现,从AbstractMap继承Map实现

  • 该类是私有的或包私有的,您可以确定它的equals方法永远不会被调用
    // Class with a typical equals method
    
    public final class PhoneNumber {
    
        private final short areaCode, prefix, lineNum;
    
        public PhoneNumber(int areaCode, int prefix, int lineNum) {
    
            this.areaCode = rangeCheck(areaCode,  999, "area code");
    
            this.prefix   = rangeCheck(prefix,    999, "prefix");
    
            this.lineNum  = rangeCheck(lineNum,  9999, "line num");
    
        }
    
        private static short rangeCheck(int val, int max, String arg) {
    
            if (val < 0 || val > max)
    
               throw new IllegalArgumentException(arg + ": " + val);
    
            return (short) val;
    
        }
    
        @Override public boolean equals(Object o) {
            if (o == this)
                return true;
            if (!(o instanceof PhoneNumber))
                return false;
            PhoneNumber pn = (PhoneNumber)o;
            return pn.lineNum == lineNum && pn.prefix == prefix
                    && pn.areaCode == areaCode;
        }
        ... // Remainder omitted
    
    }
    
    public class Test {
        public String a;
        public long b;
        public Date c;
        public String d;
        
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof Test)) {
                return false;
            }
            Test testOther = (Test) obj;
            return (a != null ? a.equals(testOther.a) : testOther.a == null)
                    && (b == testOther.b)
                    && (c != null ? c.equals(testOther.c) : testOther.c == null)
                    && (d != null ? d.equals(testOther.d) : testOther.d == null);
        }
    
    }