31

I've seen similar questions but they didnt help very much.

For instance I've got this Generic Class:

public class ContainerTest<T>
{

    public void doSomething()
    {
        //I want here to determinate the Class of the type argument (In this case String)
    }
}

and Another Class which uses this Container Class

public class TestCase
{

    private ContainerTest<String> containerTest;

    public void someMethod()
    {
        containerTest.doSomething();
    }
}

Is it possible to determinate the Class of the type argument in method doSomething() without having an explicit type variable/field or any constructor in ContainerTest Class?

Update: Changed format of ContainerTest Class

3
  • if (t instanceof String) ? Commented Feb 26, 2013 at 8:41
  • Can't you pass the class type as an argument only?
    – Rohit Jain
    Commented Feb 26, 2013 at 8:47
  • I might be late, but there is a great solution. Use C# (:
    – Elgirhath
    Commented May 14, 2020 at 17:29

6 Answers 6

20

The only way is to store the class in an instance variable and require it as an argument of the constructor:

public class ContainerTest<T>
{
    private Class<T> tClass;
    public ContainerTest(Class<T> tClass) {
        this.tClass = tClass;
    }

    public void doSomething()
    {
        //access tClass here
    }
}
3
  • 1
    This is exactly what I would do.
    – Bob Wang
    Commented Feb 26, 2013 at 9:02
  • 3
    Are you sure this is the only way?
    – vach
    Commented May 6, 2014 at 6:37
  • 1
    Except if you force the caller to subclass your class, yes. But it is usually not a problem…
    – Didier L
    Commented May 6, 2014 at 11:15
12

If you are interested in the reflection way, I found a partial solution in this great article: http://www.artima.com/weblogs/viewpost.jsp?thread=208860

In short, you can use java.lang.Class.getGenericSuperclass() and java.lang.reflect.ParameterizedType.getActualTypeArguments() methods, but you have to subclass some parent super class.

Following snippet works for a class that directly extends the superclass AbstractUserType. See the referenced article for more general solution.

import java.lang.reflect.ParameterizedType;


public class AbstractUserType<T> {

    public Class<T> returnedClass() {
        ParameterizedType parameterizedType = (ParameterizedType) getClass()
                .getGenericSuperclass();

        @SuppressWarnings("unchecked")
        Class<T> ret = (Class<T>) parameterizedType.getActualTypeArguments()[0];

        return ret;
    }

    public static void main(String[] args) {
        AbstractUserType<String> myVar = new AbstractUserType<String>() {};

        System.err.println(myVar.returnedClass());
    }

}
0
7

There is no "clean" way to get the Generic Type argument from within the class. Instead, a common pattern is to pass the Class of the Generic Type to the constructor and keep it as an inner property juste as done in the java.util.EnumMap implementation.

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/EnumMap.html http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/EnumMap.java

public class ContainerTest<T> {

    Class<T> type;
    T t;

    public ContainerTest(Class<T> type) {
        this.type = type;
    }

    public void setT(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

    public void doSomething() {
        //There you can use "type" property.
    }
}
2
  • 1
    This is known as a 'type token' Commented Feb 26, 2013 at 8:54
  • 2
    @ZeDonDino I link EnumMap to show that even the OpenJDK is using this pattern in a standrad implementation.
    – Renaud
    Commented Feb 26, 2013 at 10:08
5

No. It is not possible because of type erasure (the type parameters are compiled as Object + type casts). If you really need to know/enforce the type in runtime you may store a reference to a Class object.

public class ContainerTest<T> {
   private final Class<T> klass;
   private final List<T> list = new ArrayList<T>();

   ContainerTest(Class<T> klass) {
     this.klass = klass;
   }

   Class<T> getElementClass() {
     return klass;
   }

   void add(T t) {
      //klass.cast forces a runtime cast operation
      list.add(klass.cast(t));
   }
}

Use:

ContainerTest<String> c = new ContainerTest<>(String.class);
3
  • 2
    Use this with caution, this is only supported In Java SE 7 and higher.
    – ZeDonDino
    Commented Feb 26, 2013 at 8:55
  • ContainerTest<String> c = new ContainerTest<String>(String.class) //and so the diamond was born
    – Javier
    Commented Feb 26, 2013 at 8:57
  • Well, I knew this. I hoped there is a way to get the Class out of the <String> and not passing the value into a constructor or field or similar
    – ZeDonDino
    Commented Feb 26, 2013 at 9:04
4

There is a way to get the runtime type of the type parameter by using Guava's TypeToken to capture it. The solution's disadvantage is that you have to create an anonymous subclass each time you need an instance of Container.

class Container<T> {

    TypeToken<T> tokenOfContainedType = new TypeToken<T>(getClass()) {};

    public Type getContainedType() {
        return tokenOfContainedType.getType();
    }
}

class TestCase {

    // note that containerTest is not a simple instance of Container,
    // an anonymous subclass is created
    private Container<String> containerTest = new Container<String>() {};

    @Test
    public void test() {
        Assert.assertEquals(String.class, containerTest.getContainedType());
    }
}

The key of this solution is described in tha JavaDoc of TypeToken's constructor used in the code above:

Clients create an empty anonymous subclass. Doing so embeds the type parameter in the anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.

2
  • Wow, a downvote, that's nice... Could you at least drop a comment on why you don't like it?
    – zagyi
    Commented Feb 26, 2013 at 11:25
  • This is an interesting solution but I think it would be better suited for reflexion like guava does than for this question's use case. The problem with this solution is that it requires to create an anonymous class in each location where you instantiate it. (notice I am not the downvoter)
    – Didier L
    Commented Feb 26, 2013 at 12:38
-3

If You can define like this

public class ContainerTest<T>
{

    public void doSomething(T clazz)
    {

    }
}

Then it is possible

1
  • 1
    I would like to invoke this method without any arguments.
    – ZeDonDino
    Commented Feb 26, 2013 at 8:54

Not the answer you're looking for? Browse other questions tagged or ask your own question.