Best practices regarding equals: to overload or not to overload?

后端 未结 8 961
刺人心
刺人心 2020-12-09 02:48

Consider the following snippet:

import java.util.*;
public class EqualsOverload {
    public static void main(String[] args) {
        class Thing {
                 


        
相关标签:
8条回答
  • 2020-12-09 03:17

    If you have one single field as in your example, I think

    @Override public boolean equals(Object o) {
        return (o instanceof Thing) && (this.x == ((Thing) o).x);
    }
    

    is the way to go. Anything else would be overly complicated imo. But if you add a field (and don't want to pass the 80-column recommendation by sun) it would look something like

    @Override public boolean equals(Object o) {
        if (!(o instanceof Thing))
            return false;
        Thing t = (Thing) o;
        return this.x == t.x && this.y == t.y;
    }
    

    which I think is slightly uglier than

    public boolean equals(Thing o) {
        return this.x == o.x && this.y == o.y;
    }
    
    @Override public boolean equals(Object o) {
        // note that you don't need this.equals().
        return (o instanceof Thing) && equals((Thing) o);
    }
    

    So my rule of thumb is basically, if need to cast it more than once in override-only, do the override-/overload-combo.


    A secondary aspect is the runtime overhead. As Java performance programming, Part 2: The cost of casting explains:

    Downcast operations (also called narrowing conversions in the Java Language Specification) convert an ancestor class reference to a subclass reference. This casting operation creates execution overhead, since Java requires that the cast be checked at runtime to make sure that it's valid.

    By using the overload-/override-combo, the compiler will, in some cases (not all!) manage to do without the downcast.


    To comment on @Snehal point, that exposing both methods possibly confuses client-side developers: Another option would be to let the overloaded equals be private. The elegance is preserved, the method can be used internally, while the interface to the client side looks as expected.

    0 讨论(0)
  • 2020-12-09 03:20

    Let me share an example of "buggy code" with Overloaded equals:

    class A{
        private int val;
    
        public A(int i){
            this.val = i;
        }
    
        public boolean equals(A a){
            return a.val == this.val;
        }
    
        @Override
        public int hashCode() {
            return Objects.hashCode(this.val);
        }
    }
    
    public class TestOverloadEquals {
    
        public static void main(String[] args){
            A a1 = new A(1), a2 = new A(2);
            List<A> list = new ArrayList<>();
            list.add(a1);
            list.add(a2);
            A a3 =  new A(1);
    
            System.out.println(list.contains(a3));
        }
    }
    
    0 讨论(0)
提交回复
热议问题