Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check instance of generic?

Tags:

java

oop

Hello I have a method that should return different results depending on the type.

I can do like this to check the generic type.

public <T> T search(final String query){
 T returnValue = null;
 if (returnValue instanceof String){ }
 if (returnValue instanceof Integer){ }
 if (returnValue instanceof MyObject){ }

But why can't I do like this?

public <T> T search(final String query){
 T returnValue = null;
 if (T instanceof String){ }
 if (T instanceof Integer){ }
 if (T instanceof MyObject){ }

Calling code.

String id = myObjcet.<String> search("select ...");
like image 979
Farmor Avatar asked Sep 08 '11 16:09

Farmor


3 Answers

Java implements generics "by erasure". That means that at runtime there is (nearly) no knowledge of generics at all. Instead, the compiler checks for generics, but under the cover it converts everything to Object (or to the nearest generics boundary).

If you decompile that method using javap, you'll see that it reads :

public Object search(...

Every reference to T is removed.

This is a serious limitation of generics in Java, which is reflected often also in the JRE classes with constructs like :

SomeClass<String> x = new SomeClass<String>(String.class);

Where the third repetition of String (String.class) is needed because the constructor needs to know which class it is operating on.

This paradigm, despite being horrible, could solve your problem.

Informations about generics are actually contained in the .class files, as metadata, they can be inspected using reflection and up to some extent also resolved. However, this is not possible in a case like yours, but it is for example used by ORMs on list getters. for example, using Hibernate, a getter like this :

public List<Group> getGroups() {

Can be inspected by Hibernate so that it knows that the list is supposed to hold instances of Group, adapting its queries accordingly.

(However, even if generics where not implemented this way, T is not an instance, it is a class, writing String instanceof String is equally wrong. It should be if (T.equals(String.class)) )

like image 129
Simone Gianni Avatar answered Sep 25 '22 22:09

Simone Gianni


Because T is erased at runtime. It's only there at compile time. returnValue is the variable -- it is present at runtime.

like image 26
hvgotcodes Avatar answered Sep 23 '22 22:09

hvgotcodes


public <T> T search(Class<T> clazz, String query){
 T returnValue = null;
 if (clazz==String.class){ }
 if (clazz==Integer.class){ }
 if (MyObject.clazz.isAssignableFrom(clazz){ }


String id = myObjcet.search(String.class, "select ...");
like image 26
irreputable Avatar answered Sep 22 '22 22:09

irreputable