Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!

like image 666
David T. Avatar asked May 05 '13 08:05

David T.


People also ask

How does equals () method work What does it do?

The equals() method compares two strings, and returns true if the strings are equal, and false if not. Tip: Use the compareTo() method to compare two strings lexicographically.

How do you declare a generic method How do you invoke a generic method?

Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.


2 Answers

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

like image 154
Evgeniy Dorofeev Avatar answered Sep 21 '22 05:09

Evgeniy Dorofeev


Evgeniy's solution and Michal's reasoning are correct - you don't need to worry about the type of T here. The reason is that the equals method doesn't depend on generics to work correctly. Instead, it is declared by Object and it takes an Object. Thus, it's responsible for checking the runtime type of whatever was passed in.

If this happens to be SingularNode<String> and you compare it with a SingularNode<Integer>, then ((SingularNode<?>)other).value.equals(value) is perfectly fine because calling Integer.equals with a String argument will correctly return false.

like image 39
Paul Bellora Avatar answered Sep 22 '22 05:09

Paul Bellora