• Post Reply Bookmark Topic Watch Topic
  • New Topic

Generics and instanceof  RSS feed

 
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It seems like one cannot use instanceof in a generics-based class for equals() to test an object against a generic type T due to type erasure. Is this correct and one must perform tedious checks against null, with getClass(), etc.? Or, is there a way to use instanceof in this case?

Thanks,
Steve
 
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You start out talking about using instanceof with generics and then suddenly make a huge leap to checking for null values? What are you trying to do?
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Ken,

Thank you for your help. If instanceof will not work on a parameterized type, then presumably one needs to check for the correctness of a class before checking for meaningful equality in equals(), since equals must take an object as its argument in order to override the super equals(). That check would need to also check the passed arg for nullness.

Is there a way to take the simple approach and just use instanceof(), like for a non-generic class?

Thanks,
Steve
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm still not sure what your question is, perhaps provide a code example? You can't use instanceof because the generic type will be erased to it's upper bounds. If all you want to check is the upper bounds then you're okay, otherwise you'll have problems.
 
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Use the equals() method in T (the parameterized type) to check for null, correctness of type etc.

 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ken,

The problem is related to the implemention of the equals() method. You usually need to verify the object type so that you don't get a ClassCastException.

class GenClass<T>
{
T obj;
public GenClass(T t)
{
obj = t;
}
public boolean equals(Object o)
{
// if (o instanceof T) return false; won't work due to erasure!!!
// substitute statements - are they necessary or is there a way to still
// use instanceof?
if (o == null)
return false;
if (obj == o)
return true;
if (o.getClass() != T.getClass()
return false;
....
return //true or false based on the situation.
}
}

Thanks,
Steve
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Garrett,

Thanks for your help. I tried your suggestion and it compiles. One question, please... Is it really the case that one does not need to consider the parameter type in the equals() method? The reason that I am asking is that one could create an object of Integer and compare it to an object of Long. I am under the impression that the only way that one could do a meaningful comparison is to ensure that an Integer is not equal to a Long and the only way to ensure this is to know the parameterized type. Is this wrong? If no, how does one implement an equals successfully when the type information is lost due to erasure?

Thanks,
Steve
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Manuel Comnenus:
Ken,

The problem is related to the implemention of the equals() method. You usually need to verify the object type so that you don't get a ClassCastException.

class GenClass<T>
{
T obj;
public GenClass(T t)
{
obj = t;
}
public boolean equals(Object o)
{
// if (o instanceof T) return false; won't work due to erasure!!!
// substitute statements - are they necessary or is there a way to still
// use instanceof?
if (o == null)
return false;
if (obj == o)
return true;
if (o.getClass() != T.getClass()
return false;
....
return //true or false based on the situation.
}
}

Thanks,
Steve


Here's my confusion Manuel/Steve, why are you trying to compare the Object to an instance member of your GenClass instead of to GenClass itself? Why can't you simply invoke o.equals(T) for whatever comparison is needed?



The reason I find this incredibly weird is I can't fathom your doing anything in that block that would require a cast to begin with, otherwise I don't see how your code would work regardless of whether or not instanceof worked.
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Are you talking about something like this?



That of course will not work because there is only one Foo class and no matter what T is instanceof will always return true if o is an instance of Foo.
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Garrett Rowe:
Use the equals() method in T (the parameterized type) to check for null, correctness of type etc.



That'll work in a certain in context, but in many, arguably most, it won't. You'd have to first a) want the "tee" variables being equal to be a requirement and b) be able to rely on the implementations of "tee", which may not even be of the same type, to have an equals() which returns consistently with your requirements.
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Ken,

Thanks for your continued responses. Does this mean, then, that one cannot have, let's say, a TreeSet of a generic class? One needs to override both equals() and hashcode(). Right?

Thanks,
Steve
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ken,

I forgot to mention that my name is actually Steve. Since the name that I would use as my screen name was already taken and the naming conventions forbid embedded digits, I decided to use the name of a 12th century character so that I wouldn't have to spend a lot of time thinking of name variations that weren't already used.

Steve
 
Garrett Rowe
Ranch Hand
Posts: 1296
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ken Blair: That'll work in a certain in context, but in many, arguably most, it won't. You'd have to first a) want the "tee" variables being equal to be a requirement and b) be able to rely on the implementations of "tee", which may not even be of the same type, to have an equals() which returns consistently with your requirements.

After thinking about this statement for a bit, I really can't think of a concrete case where a class that uses generics at the class level, and overrides equals(), wouldn't want to satisfy both these conditions. Could you please provide an example of the type of case you were describing.
[ April 27, 2006: Message edited by: Garrett Rowe ]
 
Ranch Hand
Posts: 584
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Manuel,

The data type assurance is checked only during compile time. When your .class file is generated no type assurance is written on that.

that's why you cannot check a generic variable against generic type by using the instance of operator.

You can check your generic variable only against a raw type, as follows :

 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If I have two ImageRenderer<T> instances and I want to consider them equal if and only if they are capable of rendering the same type of image (T) then whether or not the image in one is equal to the image in another is irrelevent, only their type matters.
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Edisandro and Ken,

Thank you for your advice. I might not be asking my question clearly. I am interested in what takes place with a Collection of a generic class. So,
the scenario looks more like this:

class GenClass<T>
{
T obj;
public GenClass(T obj)
{
this.obj = obj;
}
public boolean equals(Object o)
{
//some code like the following, if it works, or if, even better, if
//there is a way to make instanceof work and eliminate all of the tests.

if (o == null)
return false;
if (o == this)
return true;
if ((o.getClass() != obj.getClass())
return false;
//the following code would do some type of comparison that requires obj
//to be downcast.
}
}

class Test
{
public static void main(String... args)
{
GenClass<Integer> gc1 = new GenClass<Integer>(11);
GenClass<Long> gc2 = new GenClass<Long>(22L);
GenClass<Short> gc3 = new GenClass<Short>((short)5);
GenClass<String> gc4 = new GenClass<String>("Ouch");
Set<GenClass> ts = new TreeSet<GenClass>();
ts.add(gc1);
ts.add(gc4);
ts.add(gc2);
ts.add(gc3);
}
}

Thanks,
Steve
 
Ranch Hand
Posts: 1608
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
ContractualJ fixes the mess that this post is eluding to.
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your example certainly seems like a perfect candidate for what Garrett posted.
 
Manuel Comnenus
Ranch Hand
Posts: 86
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tony,

I looked at the link that you provided and apparently, this is a product that you developed. I'll be sure to take a very close look at it.

Thank you for your help.

Steve
 
Ranch Hand
Posts: 1923
Linux Postgres Database Scala
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ken Blair:
If I have two ImageRenderer<T> instances and I want to consider them equal if and only if they are capable of rendering the same type of image (T) then whether or not the image in one is equal to the image in another is irrelevent, only their type matters.


Isn't that a very relaxed idea of being equal?
Wouldn't one normally tend to use an interface RendersXPM here?
 
Ken Blair
Ranch Hand
Posts: 1078
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I know it's a naive example, I'm just trying to make the point that invoking equals() on the instance variable isn't necessarily a requirement of equality. If I just want to verify that they have the same type then equals() isn't necessarily going to do that for me.

And no, you wouldn't create a RendersXPM if you wanted to use it in a higher level class that had zero knowledge of the image type.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!