Overriding “equals” method: how to figure out the type of the parameter?

前端 未结 9 1295
栀梦
栀梦 2021-02-05 07:47

I\'m trying to override equals method for a parameterized class.

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return t         


        
相关标签:
9条回答
  • 2021-02-05 08:26

    The suggestions to retain a reference to E's type with a Class object seem inefficient (that's a lot of pointless references to a Class taking up memory) and pointless for your problem.

    It's not generally true that Foo<Bar> andFoo<Baz> should be unequal. So you don't need E. And, in the code you wrote, you don't even need it to compile. Simply cast to Tuple<?>, since that is truly all you know about Tuple at that point. It still compiles and all.

    If you are passed Tuples with data of two wildly different types, those elements will not be equals, and your method will return false, as desired. (One hopes -- depends on those types implementing equals sanely.)

    0 讨论(0)
  • 2021-02-05 08:32

    Because of erasure you can't. About the best you could do is store in the tuple class the type you plan for the Tuple to hold in a "java.lang.Class" field member. Then you could compare those fields to make sure the tuple class is holding the same types.

    Also see this thread: What is the equivalent of the C++ Pair<L,R> in Java?

    It would help if you post more about your class. I'm thinking the unchecked cast and your number of fields you equate means it should be Tuple<E,F> no?

    EDIT: here is a useful Pair class I use regularly (you can adapt your Tuple class if needed). Note, similiar to suggestions by others this class just lets the contained members decide the question of equality. Your use case is what should determine whether equality is really based on the type of the contained members.

    /**
     * Adapted from http://forums.sun.com/thread.jspa?threadID=5132045
     * 
     * 
     * @author Tim Harsch
     *
     * @param <L>
     * @param <R>
     */
    public class Pair<L, R> {
    
        private final L left;
        private final R right;
    
        public R getRight() {
            return right;
        } // end getter
    
        public L getLeft() {
            return left;
        } // end getter
    
        public Pair(final L left, final R right) {
            this.left = left;
            this.right = right;
        } // end constructor
    
        public static <A, B> Pair<A, B> create(A left, B right) {
            return new Pair<A, B>(left, right);
        } // end factory method
    
        @Override
        public final boolean equals(Object o) {
            if (!(o instanceof Pair<?,?>))
                return false;
    
            final Pair<?, ?> other = (Pair<?, ?>) o;
            return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight());
        } // end method
    
        public static final boolean equal(Object o1, Object o2) {
            if (o1 == null) {
                return o2 == null;
            }
            return o1.equals(o2);
        } // end method
    
        @Override
        public int hashCode() {
            int hLeft = getLeft() == null ? 0 : getLeft().hashCode();
            int hRight = getRight() == null ? 0 : getRight().hashCode();
    
            return hLeft + (37 * hRight);
        } // end method
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append('<');
            if( left == null ) {
                sb.append("null");
            } else {
                sb.append(left.toString());
            } // end if
            sb.append(',');
            if( right == null ) {
                sb.append("null");
            } else {
                sb.append(right.toString());
            } // end if
            sb.append('>');
            return sb.toString();
        } // end method
    } // end class
    
    0 讨论(0)
  • 2021-02-05 08:35

    Since generics are erased at compile time, you basically can't. At runtime, any type parameter is gone, and as far as the JVM is concerned, they are exactly the same in all respects.

    The way to work around that is to store a Class field that represents the type, and create the object with that type in the constructor.

    A sample constructor:

    public class Tuple < E > {
    
        public Tuple(Class<E> c) {
            //store the class
        }
    
    }
    

    Or you could use a factory:

    public static <E> Tuple <E> getTuple(Class<E> type) {
        // Create and return the tuple, 
        // just store that type variable in it 
        // for future use in equals.
    }
    
    0 讨论(0)
提交回复
热议问题