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 formSingularNode<?>
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!
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.
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.
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
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With