Reputation: 1080
I'd like to know if something like this is possible in Java (mix of C++ and Java ahead)
template<typename T> bool compare(Wrapper wrapper) {
if(wrapper.obj.getClass().equals(T.class))
return true
return false
}
To clarify, the function takes in an object which contains a java.lang.object, but I'd like to be able to pass that wrapper into this generic comparison function to check whether that object is of a particular type, ie
if(compare<String>(myWrapper))
// do x
Upvotes: 0
Views: 70
Reputation: 181859
You cannot reference static members of a type parameter (such as you try to do in the form of T.class
). You also cannot use them meaningfully in instanceof
expressions. More generally, because Java generics are implemented via type erasure, you cannot use type parameters in any way at run time -- all type analysis is performed statically, at compile time.
Depending on exactly what you're after, there are at least two alternative approaches.
The first, and more usual, is to ensure that the necessary types can be checked statically. For example, you might parameterize your Wrapper
class with the type of the object it wraps. Then, supposing that you use it in a program that is type-safe, wherever you have a Wrapper<String>
you know that the wrapped object is a String
.
That doesn't work so well if you want to verify the specific class of the wrapped object, however, when the class to test against is not final
. In that case, you can pass a Class
object, something like this:
<T> boolean compare(Wrapper<? super T> wrapper, Class<T> clazz) {
return wrapper.obj.getClass().equals(clazz);
}
That checks the class of the wrapped object against the specified class, allowing the method to be invoked only in cases where static analysis allows that it could return true
.
You can actually combine those two approaches, if you like, to create a Wrapper
class whose instances can hold only members of a specific class, as opposed to any object that is assignable to a given type. I'm not sure why you would want to do that, though.
Upvotes: 1
Reputation: 43456
No, it's not possible due to erasure. Basically, the compare
method has no idea what T
is. There's only one compare
method (as opposed to C++, where there's one per T
), and it isn't given any information about how it was invoked (ie, what the caller considered its T
to be).
The typical solution is to have the class (or method) accept a Class<T> cls
, and then use cls.isInstance
:
public <T> boolean compare(Wrapper wrapper, Class<T> cls) {
return cls.isInstance(wrapper.obj);
}
// and then, at the call site:
if (compare(wrapper, Foo.class)) {
...
}
Of course, this means that the call site needs to have the Class<T>
object. If that call site is itself a generic method, it needs to get that reference from its caller, and so on. At some point, somebody needs to know what the specific type is, and that somebody passes in Foo.class
.
Upvotes: 2