Is int.class.isInstance(Object) a contradiction?
Asked Answered
P

2

6

Here's an example:

public boolean check(Class<?> clazz, Object o)
{
    return clazz.isInstance(o);
}

check(int.class, 7); // returns false

Since isInstance accepts an Object, it won't work with int, because int is a primitive type and gets autoboxed to Integer. So is it at all possible to write a generic check method? Or should I make sure that clazz is of type Class<? extends Object>?

Policlinic answered 28/4, 2013 at 17:20 Comment(4)
Instead of using not very meaningful tags such as int, types or even isintance, you should tag the question with the language you are using. That would attract more viewers, and therefore increases the chance for you to receive a satisfying answer.Brigittebriley
Sry, I completely forgot that. ...I guess java has become natural to me :DPoliclinic
Did you read this answer yet?Withstand
Note that Class<?> is the same as Class<? extends Object>. int.class and Integer.class both have the type Class<Integer>, which is unfortunately misleading in the former case.Pricket
H
6

Not all Class objects represent classes / reference types; there are also Class objects that represent primitive types. This is useful because in using reflection with fields and methods, you often need to specify their type, and it can be a primitive type. So Class is used to represent all such pre-generics types.

However, many of the methods of the Class class do not make sense for primitive types. For example, it is impossible for an object to be instanceof int. Therefore, the analogous .isInstance() method will always return false. Since the parameter of that method is type Object, it is simply impossible from a language point of view for what you pass in there to be of a primitive type.

Sure, in Java 5+ when you pass a primitive to a parameter of type Object, it undergoes autoboxing, but the fact that it underwent autoboxing means that what was passed is actually a reference to an object. Reference types and primitive types are distinct. A parameter is either a reference type or primitive type. Thus you cannot write a method that can take a "reference or primitive".

What you may be asking, in your example, is to detect that the object was autoboxed from a primitive, and compare it to a primitive type. However, it is impossible to detect whether the caller autoboxed it, since autoboxing is a completely caller-side operation that happens before the call.

However, assuming it was autoboxed, you know what type it should have gone to. If you are expecting an int, and it is autoboxed and passed to your method, it should be an instance of Integer. Thus, what you could do is, when clazz represents a primitive type, instead perform the check on its wrapper class. Thus, when it sees that clazz is int.class, substitute it with Integer.class, and then perform the check. Note that this way still doesn't tell whether what was passed as the o parameter was autoboxed.

Heartwhole answered 29/4, 2013 at 1:29 Comment(3)
I did some research, seems there is no generic method to get the wrapper class of a primitive type, or a generic way to get the TYPE field of a wrapper class. I guess I have to hard code a map and perform a lookup thereon.Policlinic
@Policlinic If you happen to be using Guava, the Primitives class handles those use cases already.Pricket
Thanks but, the guava methods also rely on a hard coded map. Anyway, great answers and comments here, I learned a lot!Policlinic
R
3

There is no int class in Java. Its Integerclass. 7 is converted to Integer.valueOf(7), and int.class will be converted to Integer.classas per JLS.

If p is the name of a primitive type, let B be the type of an expression of type p after boxing conversion. Then the type of p.class is Class<B>.

Since Integer is a class object, while int is primitive type. So, most methods of Class such as isInstance, isAssignableFrom etc which operates on Objects are invalid in the context of int.class, hence you see that contradiction.

check(Integer.class, 7);

should give expected result.

Reiterate answered 28/4, 2013 at 17:25 Comment(4)
I use a form of the check method in a context of a generic setter, where I extract the type information from the attribute to set and compare it with the setter's parameter type. So I should prohibit primitive types for the attributes I want to set?Policlinic
It would be useful to show the code for this generic setter. If it is like <T> void setSomething(T theThing), you aren't going to be able to use primitives directly anyway - they'll always be autoboxed, because generic types can only be Objects, never primitives.Lammers
You can see the code in another question I asked on SO #16226123Policlinic
"and int.class will be converted to Integer.classas per JLS" This is absolutely wrong. int.class is NOT the same as Integer.class. Instead, int.class is equal to Integer.TYPE.Heartwhole

© 2022 - 2024 — McMap. All rights reserved.