sjngm
sjngm

Reputation: 12861

How to get class of generic type when there is no parameter of it?

I just learned about this fine looking syntax

Collections.<String>emptyList()

to get an empty List with elements which are supposedly of type String. Java's source looks like this:

public static final List EMPTY_LIST = new EmptyList<Object>();
:
public static final <T> List<T> emptyList() {
  return (List<T>) EMPTY_LIST;
}

Now if I code a method in that way where the generic type does not appear in the parameter list, is there any way how I can access the actual class that becomes T?

I'm saying, up to now my approach to code the same thing would have been

private <T> T get(String key, Class<T> clazz) {
  // here I can do whatever I want with clazz, e.g.:
  return clazz.cast(value);
}

If I removed the clazz-parameter I wouldn't be able to do the cast(). Obviously I could do

  return (T) value;

but that gives me the usual warning Type safety: Unchecked cast from Object to T. Ok, @SuppressWarnings("unchecked") helps here, but actually I want to do something with the intended return type of the method. If I add a local variable

T retValue;

I'd have to initialise it with something, null doesn't help. After I assign it like

@SuppressWarnings("unchecked")
T retValue = (T) value;

I could do, e.g.

retValue.getClass().getName()

but if the cast fails I end up with no information about T again.

Since Java (or at least my Java 6) does not have the generic info any more during runtime, I currently can't think of a way to do this. Is there a way? Or do I have to stick with my "old" approach here?

Please note that the example I lined out is very simple and doesn't make much sense. I want to do more complicated stuff here, but that's out of the scope.

Upvotes: 9

Views: 7521

Answers (5)

ivanesko
ivanesko

Reputation: 1

I find out that there is one solution for getting Class<?> from T:

public class Action<T>{
}

public Class<?> getGenericType(Object action) throws ClassNotFoundException{
   Type type =
   ((ParameterizedType)action.getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];
   String sType[] = type.toString().split(" ");

   if(sType.length != 2)
      throw new ClassNotFoundException();

   return Class.forName(sType[1]);
}

The usage of code above:

Action<String> myAction = new Action<String>();

getGenericType(myAction);

I did not tested this with primitive types (int, byte, boolean).

I think that it is not very fast, but you do not have to pass Class<?> to constructor.

EDIT:

The usage above is not right, because generic superclass is not available for Action<String>. Generic super class will be available only for inherited class like class ActionWithParam extends Action<String>{}. This is reason why I changed my mind and now I suggest to pass class parameter to constructor, too. Thanks to newacct for correction.

Upvotes: -2

Peter Lawrey
Peter Lawrey

Reputation: 533492

If you want the generic type at runtime you need to either have it as a field or create a sub-class of a type for a specific combination of types.

e.g.

List<String> list = new ArrayList<String>() {}; // creates a generic sub-type
final Class type = (Class) ((ParameterizedType) list.getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println(type);

prints

class java.lang.String

Upvotes: 6

biziclop
biziclop

Reputation: 49744

retValue.getClass().getName() will always return the runtime type of the object and not the class name of the parameter type.

If you want to grab the parameter class, there's no other way than to use your first solution. (That is, pass the class object explicitly.)

Upvotes: 2

korifey
korifey

Reputation: 3509

You can't, unfortunately. All generics and type parameters are erased in runtime. So in runtime the type of your T is simply Object

Upvotes: 4

Alan Geleynse
Alan Geleynse

Reputation: 25139

As you mentioned, Java generics are build time only. They are not used at run time.

Because of this, the old approach you were using will be your only way to accomplish this.

Upvotes: 1

Related Questions