How to implement "equals" method for generics using "instanceof"?

David T. picture David T. · May 5, 2013 · Viewed 29k times · Source

I have a class that accepts a generic type, and I want to override the equals method in a non-awkward way (i.e. something that looks clean and has minimal amount of code, but for a very general use case).

Right now I have something like this:

public class SingularNode<T> {
    private T value;

    @SuppressWarnings("unchecked")
    @Override
    public boolean equals(Object other){
        if(other instanceof SingularNode<?>){
            if(((SingularNode<T>)other).value.equals(value)){
                return true;
            }
        }
        return false;
    }
}

Which, I'm guessing, is pretty flawed - I'm doing a cast to SingularNode<T> on the other object, which could potentially throw an error.

Another thing is - when I do if(other instanceof SingularNode<?>) I'm actually not checking exactly the right thing. I actually want to check against type T and not type ?. Whenever I try to make the ? into T, I get some error like:

Cannot perform instanceof check against parameterized type SingularNode<T>. Use the form SingularNode<?> instead, since further generic type information will be erased at runtime

How can I get around this? Is there some way to do T.class.isInstance(other); ?

I suppose there's one really ugly hack solution like this:

@SuppressWarnings("unchecked")
public boolean isEqualTo(Class<?> c, Object obj){
    if(c.isInstance(obj) && c.isInstance(this)){
        if(((SingularNode<T>)obj).value.equals(value)){
            return true;
        }
    }
    return false;
}

But that just looks really awkward with the extra method parameter, and it's also not a built-in function like equals is.

Any one who understand generics please explain this? I'm not that proficient with Java, as you can clearly see, so please explain with a tad bit more detail!

Answer

Evgeniy Dorofeev picture Evgeniy Dorofeev · May 5, 2013

This version gives no warnings

public boolean equals(Object other){
    if (other instanceof SingularNode<?>){
        if ( ((SingularNode<?>)other).value.equals(value) ){
            return true;
        }
    }
    return false;
}

As for casting to SingularNode<T> it does not help anything, you cannot assume that T can be anything but Object.

Learn more about how generics are compiled in Java at

https://docs.oracle.com/javase/tutorial/java/generics/erasure.html