561

How can I achieve this?

public class GenericClass<T>
{
    public Type getMyType()
    {
        //How do I return the type of T?
    }
}

Everything I have tried so far always returns type Object rather than the specific type used.

Elrond_EGLDer
  • 47,430
  • 25
  • 189
  • 180
Glenn
  • 5,635
  • 3
  • 13
  • 3

27 Answers27

353

As others mentioned, it's only possible via reflection in certain circumstances.

If you really need the type, this is the usual (type-safe) workaround pattern:

public class GenericClass<T> {

     private final Class<T> type;

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

     public Class<T> getMyType() {
         return this.type;
     }
}
Henning
  • 15,233
  • 3
  • 49
  • 65
  • 65
    I like this answer but it's a little cumbersome to instantiate: GenericClass g = new GenericClass(AnotherClass.class); – Eliseo Ocampos Aug 16 '13 at 16:21
  • 1
    Its even more verbose if you use a dao/factory/manager approach. `Foo foo1 = GetDao(Foo.class).get(Foo.class, 1)` – djmj Oct 16 '14 at 21:55
  • @djmj, if you save `Foo.class` in DAO, you don't need to pass it in methods. And vice versa. Actually your example will be looking like `Foo foo1 = GetDao(Foo.class).get(1);`. It's not so bad I think. – naXa Dec 10 '14 at 08:11
  • 2
    Thats true, but not working in all cases like stateless remote beans which are instantiated by container/reflection. – djmj Dec 10 '14 at 10:24
  • 6
    Just as a follow-up to my previous comment - after lot of pain playing with reflection, I ended up using this answer. – Tomáš Zato - Reinstate Monica May 01 '15 at 17:08
  • 21
    You can get around the superfluous reference by providing a generic static factory method. Something like `public static GenericClass of(Class type) {...}` and then call it as such: `GenericClass var = GenericClass.of(String.class)`. A bit nicer. – Joeri Hendrickx Aug 01 '16 at 20:04
  • @Henning Please check my answer. I think it is better. I just found it today: https://stackoverflow.com/a/64504193/9432967 – Omid.N Oct 23 '20 at 16:55
284

I have seen something like this

private Class<T> persistentClass;

public Constructor() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                            .getGenericSuperclass()).getActualTypeArguments()[0];
 }

in the hibernate GenericDataAccessObjects Example

FrVaBe
  • 44,054
  • 15
  • 110
  • 143
  • 87
    This technique works where the type parameter is defined on the immediate superclass, but it fails if the type parameter is defined elsewhere in the type hierarchy. For handling more complex cases something like [TypeTools](https://github.com/jhalterman/typetools) can be used. The docs include an example of a more sophisticated Generic DAO. – Jonathan Aug 19 '11 at 04:34
  • 27
    This only returns the actual type parameters used when a _CLASS_ implements / extends something that has generic declarations, it does not return the actual type parameters used when an _INSTANCE_ is instantiated. In other words, it **CAN** tell that in `class A implements Comparable`, the actual type parameter is `String`, but it **CANNOT** tell that in `Set a = new TreeSet()`, the actual type parameter is `String`. In fact, the type parameter information is "erased" after compilation, as explained in other answers. – Siu Ching Pong -Asuka Kenji- Jan 18 '15 at 05:44
  • 1
    You can also get a generic return type with something like this: ` TYPE getType(){return ((ParameterizedType)(new ArrayList()).getClass().getGenericSuperclass()).getActualTypeArguments()[0].getClass();}` (sorry for the bad formatting). As far as I can tell, Lists don't always lose their generic types at runtime. – mailmindlin Feb 05 '15 at 16:54
  • 35
    I am getting `java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType` for this answer. – Tomáš Zato - Reinstate Monica May 01 '15 at 13:14
  • 4
    This approach can also be achieved using `Class-Mate` from the Jackson folks. I wrote a gist here https://gist.github.com/yunspace/930d4d40a787a1f6a7d1 – yunspace Aug 19 '15 at 00:16
  • @yunspace could you please provide the link to that library? – ieXcept Jun 22 '16 at 12:17
  • @ieXcept class-mate is here https://github.com/FasterXML/java-classmate – yunspace Jun 23 '16 at 13:53
  • @yunspace Nice recommendation. For me the solution to get the erased type for `clazz` inside a method like `public void work(Class clazz)` was to use: `new TypeResolver().resolve(clazz).getErasedType()`. – markdsievers Oct 19 '16 at 03:23
  • 5
    @TomášZato Calling simply the code above returned the same exception for me. I know it's a bit late, but anyway, in my case, I had to call `(Class) ((ParameterizedType)getClass().getSuperclass().getGenericSuperclass()).getActualTypeArguments()` to get to actual type arguments. – AndrewMcCoist Feb 13 '17 at 18:39
  • Nice hack! Helped me a lot in my tests! – Nikolay Chernov Feb 16 '17 at 13:13
  • I am getting the same error as @TomášZato . My context is JUnit test execution. Any thoughts? – Rosberg Linhares May 09 '19 at 20:12
  • Why is there only a method `getGenericSuperclass()` and not `getGenericClass()`? – Luke Hutchison Jan 27 '21 at 13:40
  • For a class with arbitrarily long inheritance, I think you could loop over `getClass()` and `getSuperClass()` until the `getName()` method of the class returns the name of the target parent class, at which point you can call `getGenericSuperclass()` as above. – Tama Yoshi May 29 '21 at 23:40
110

Generics are not reified at run-time. This means the information is not present at run-time.

Adding generics to Java while mantaining backward compatibility was a tour-de-force (you can see the seminal paper about it: Making the future safe for the past: adding genericity to the Java programming language).

There is a rich literature on the subject, and some people are dissatisfied with the current state, some says that actually it's a lure and there is no real need for it. You can read both links, I found them quite interesting.

Jacob van Lingen
  • 6,165
  • 3
  • 39
  • 68
ewernli
  • 36,434
  • 4
  • 82
  • 119
  • 212
    Of course we are dissatisfied, .NET has much better generic handling mechanism – Pacerier Mar 06 '12 at 12:35
  • 6
    @Pacerier: but reified generics alone would not bring Java to the level of .NET. Value types an specialized code for those is at least equally important for why .NET is better in the generics area. – Joachim Sauer Jul 19 '12 at 14:34
  • @JoachimSauer, yes value types. I'd always wanted those in java. Btw what do you mean by specialized code? – Pacerier Jul 19 '12 at 17:31
  • @Pacerier: well, in Java an array of non-primitives is always "one-reference-per-element" large. With specialized code for value types that could be "x-bytes-per-element" where *x* is the size of the value type. I.e. you could use real packed arrays as used in C/C++. – Joachim Sauer Jul 19 '12 at 18:45
  • @JoachimSauer, lol I'd thought you said "value types" and "specialized code" as if they were two different things. – Pacerier Jul 19 '12 at 19:30
  • @Pacerier: well, there *could* be a naive implementation of value types as "the same as reference types, except they can be freely copied". From a functional perspective that would have the same effect, but only with specialized code do you get the *real* benefits of value types. – Joachim Sauer Jul 21 '12 at 09:41
  • Doesn't FrVaBe's answer imply that the generic type IS present at runtime? It seems that Java simply doesn't provide a convenient mechanism for accessing it. – spaaarky21 Apr 24 '14 at 19:02
  • 3
    @spaaarky21 No, generic type parameters are removed during compilation (so-called "erasure", you can google it). The trick in FrVaBe's answer works only if the type params of the superclass are known statically (see the first commment by Johnathn) – ewernli Apr 25 '14 at 12:53
  • 1
    Java type erasure is a historical design flaw; more code has been written to get around it than was written to implement it. – Abhijit Sarkar Oct 26 '18 at 22:30
77

Use Guava.

import com.google.common.reflect.TypeToken;
import java.lang.reflect.Type;

public abstract class GenericClass<T> {
  private final TypeToken<T> typeToken = new TypeToken<T>(getClass()) { };
  private final Type type = typeToken.getType(); // or getRawType() to return Class<? super T>

  public Type getType() {
    return type;
  }

  public static void main(String[] args) {
    GenericClass<String> example = new GenericClass<String>() { };
    System.out.println(example.getType()); // => class java.lang.String
  }
}

A while back, I posted some full-fledge examples including abstract classes and subclasses here.

Note: this requires that you instantiate a subclass of GenericClass so it can bind the type parameter correctly. Otherwise it'll just return the type as T.

Cody A. Ray
  • 5,157
  • 33
  • 31
  • 1
    The constructor TypeToken(Type) is not visible – Saro Taşciyan Feb 03 '14 at 08:27
  • 3
    Notice that I create an empty anonymous subclass (see the two curly braces at the end). This uses reflection to battle Java's runtime type erasure. You can learn more here: https://code.google.com/p/guava-libraries/wiki/ReflectionExplained – Cody A. Ray Feb 04 '14 at 00:15
  • @CodyA.Ray This approach seems to battle type erasure in the most elegant way. But in your example, you're instantiating an `abstract` class. Am I missing something? – Manu Manjunath Nov 07 '14 at 06:37
  • @CodyA.Ray I'm looking for a way to do this: `CoolClass cool = new CoolClass();Class c = cool.getType(); // Should return Integer.class` – Manu Manjunath Nov 07 '14 at 06:38
  • Edited. The abstract class was a copy-paste mistake from the article that I linked: http://codyaray.com/2013/01/finding-generic-type-parameters-with-guava – Cody A. Ray Nov 07 '14 at 19:33
  • 3
    @CodyA.Ray Your code throws a `java.lang.IllegalArgumentException: class com.google.common.reflect.TypeToken isn't parameterized`. So I changed the line `new TypeToken(getClass()) { }` to `new TypeToken(getClass()) { }`. Now, code runs fine, but Type is still 'T'. See this: https://gist.github.com/m-manu/9cda9d8f9d53bead2035 – Manu Manjunath Nov 14 '14 at 11:16
  • how could you get 14 positives if your code not only is not working but also is breaking basic rules of generics in java. its perfect example of wishful thinking- if java works that way, there will not be any problems with generic parameter types instantiation. – Dominik Mar 23 '16 at 10:39
  • 3
    @Dominik Please see the updated example that you can copy and paste to test yourself. I've also added a note clarifying that you must instantiate a subclass (as shown). As a general etiquette advise, please read any linked articles and related javadocs before you accuse a poster of "wishful thinking". I've used similar production code multiple times. The Guava helpers I'm demonstrating are intended for this exact use case and their javadocs show almost an exact answer to this question. http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/reflect/TypeToken.html – Cody A. Ray Mar 23 '16 at 12:56
  • yeah right, my bad. I have read quite a bit about that approach, and previous information I have found were about using parametrized superclass which I haven't realized you are doing. Another thing is that if I try to use this approach in a constructor of the GenericClass it will return T (and I am not sure why this is the case). – Dominik Mar 23 '16 at 17:57
  • 1
    This answer works great with Java8 - I have an interface and a factory class to emit various types, and wanted users to be able to easily determine the type. In my interface I added the default method: `default Type getParameterType() { final TypeToken typeToken = new TypeToken(getClass()) {}; final Type type = typeToken.getType(); return type; }` – Richard Sand Jul 10 '17 at 21:11
  • 2
    @CodyA.Ray Since this only works with subclasses of `GenericClass`, you should make that class `abstract` so wrong usage doesn’t compile. – Martin Nov 21 '18 at 10:40
  • Note, your example with anonymous class does not require guava's `TypeToken`, see [Yaroslav Kovbas](https://stackoverflow.com/users/4688730/yaroslav-kovbas) [answer](https://stackoverflow.com/a/33997270/4413257). It would be nice to mention solution options e.g. with reference to have it in single place. – matoni Jun 18 '19 at 06:16
  • 1
    Url to ReflectionExplained has changed that's the current url https://github.com/google/guava/wiki/ReflectionExplained – Franzi Nov 19 '19 at 14:36
40

Sure, you can.

Java does not use the information at run time, for backwards compatibility reasons. But the information is actually present as metadata and can be accessed via reflection (but it is still not used for type-checking).

From the official API:

http://download.oracle.com/javase/6/docs/api/java/lang/reflect/ParameterizedType.html#getActualTypeArguments%28%29

However, for your scenario I would not use reflection. I'm personally more inclined to use that for framework code. In your case I would just add the type as a constructor param.

jpaugh
  • 5,719
  • 4
  • 33
  • 83
Joeri Hendrickx
  • 15,619
  • 4
  • 37
  • 53
  • 10
    getActualTypeArguments only returns the type arguments for the immediate class. If you have a complex type hierarchy where T could be parameterized anywhere in the hierarchy, you'll need to do a bit of work to figure out what it is. This is more or less what [TypeTools](https://github.com/jhalterman/typetools) does. – Jonathan Aug 19 '11 at 04:38
  • This answer could be improved by adding some context or a code sample. I see method in the docs and I can find it `actualTypeArguments` via my IDE's debugger but I cannot figure out how to actually access it. – Madbreaks Jul 01 '20 at 17:57
39

Java generics are mostly compile time, this means that the type information is lost at runtime.

class GenericCls<T>
{
    T t;
}

will be compiled to something like

class GenericCls
{
   Object o;
}

To get the type information at runtime you have to add it as an argument of the ctor.

class GenericCls<T>
{
     private Class<T> type;
     public GenericCls(Class<T> cls)
     {
        type= cls;
     }
     Class<T> getType(){return type;}
}

Example:

GenericCls<?> instance = new GenericCls<String>(String.class);
assert instance.getType() == String.class;
josefx
  • 14,855
  • 6
  • 34
  • 60
  • 10
    `private final Class type;` – naXa Dec 10 '14 at 08:01
  • How can I create an array type from it: `Type t = //String[]` – Pawel Cioch Feb 21 '15 at 18:27
  • @PawelCioch java.lang.reflect.Array.newInstance(elementtype, length); hope this helps (javadoc can be found here http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Array.html#newInstance-java.lang.Class-int- ) – josefx Feb 22 '15 at 17:02
  • @PawelCioch missed a .getClass() to get the type from the created array. There doesn't seem to be a direct way to get an array class. Most Java collections just use Object[] instead. – josefx Feb 23 '15 at 09:24
29
public abstract class AbstractDao<T>
{
    private final Class<T> persistentClass;

    public AbstractDao()
    {
        this.persistentClass = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
    }
}
DevDio
  • 1,355
  • 1
  • 15
  • 24
Ali Yeganeh
  • 557
  • 8
  • 13
  • 3
    I'm upvoting this answer because it's a solution that works for the question being asked. However, for those who wants to navigate upward in class hierarchy like myself with more than one Generic class, this won't work. Because you will get java.lang.object instead of actual class. – KMC May 22 '19 at 13:45
  • 6
    Please note that this solution works ONLY if the class that holds the generic type is ABSTRACT – BabaNew Aug 13 '19 at 08:30
  • @JRA_TLL you apparently did something wrong. I just used it with Java 12 and works like a charm. – Googie Jan 02 '20 at 17:20
  • If you want to navigate up in view hierarchy you can cast the genericSuperclass to Class and get the genericSuperclass. Prefereably in a loop. – fupduck Jun 02 '20 at 18:21
21

I used follow approach:

public class A<T> {

    protected Class<T> clazz;

    public A() {
        this.clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Class<T> getClazz() {
        return clazz;
    }
}

public class B extends A<C> {
   /* ... */
    public void anything() {
       // here I may use getClazz();
    }
}
Moesio
  • 2,782
  • 1
  • 24
  • 36
  • 12
    I got "Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType" with this sample code – yuyang Mar 20 '19 at 22:23
17

I dont think you can, Java uses type erasure when compiling so your code is compatible with applications and libraries that were created pre-generics.

From the Oracle Docs:

Type Erasure

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:

Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. Insert type casts if necessary to preserve type safety. Generate bridge methods to preserve polymorphism in extended generic types. Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Dimitar
  • 2,316
  • 1
  • 19
  • 28
15

Technique described in this article by Ian Robertson works for me.

In short quick and dirty example:

 public abstract class AbstractDAO<T extends EntityInterface, U extends QueryCriteria, V>
 {
    /**
     * Method returns class implementing EntityInterface which was used in class
     * extending AbstractDAO
     *
     * @return Class<T extends EntityInterface>
     */
    public Class<T> returnedClass()
    {
        return (Class<T>) getTypeArguments(AbstractDAO.class, getClass()).get(0);
    }

    /**
     * Get the underlying class for a type, or null if the type is a variable
     * type.
     *
     * @param type the type
     * @return the underlying class
     */
    public static Class<?> getClass(Type type)
    {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            return getClass(((ParameterizedType) type).getRawType());
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            Class<?> componentClass = getClass(componentType);
            if (componentClass != null) {
                return Array.newInstance(componentClass, 0).getClass();
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * Get the actual type arguments a child class has used to extend a generic
     * base class.
     *
     * @param baseClass the base class
     * @param childClass the child class
     * @return a list of the raw classes for the actual type arguments.
     */
    public static <T> List<Class<?>> getTypeArguments(
            Class<T> baseClass, Class<? extends T> childClass)
    {
        Map<Type, Type> resolvedTypes = new HashMap<Type, Type>();
        Type type = childClass;
        // start walking up the inheritance hierarchy until we hit baseClass
        while (!getClass(type).equals(baseClass)) {
            if (type instanceof Class) {
                // there is no useful information for us in raw types, so just keep going.
                type = ((Class) type).getGenericSuperclass();
            } else {
                ParameterizedType parameterizedType = (ParameterizedType) type;
                Class<?> rawType = (Class) parameterizedType.getRawType();

                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                TypeVariable<?>[] typeParameters = rawType.getTypeParameters();
                for (int i = 0; i < actualTypeArguments.length; i++) {
                    resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
                }

                if (!rawType.equals(baseClass)) {
                    type = rawType.getGenericSuperclass();
                }
            }
        }

        // finally, for each actual type argument provided to baseClass, determine (if possible)
        // the raw class for that type argument.
        Type[] actualTypeArguments;
        if (type instanceof Class) {
            actualTypeArguments = ((Class) type).getTypeParameters();
        } else {
            actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
        }
        List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>();
        // resolve types by chasing down type variables.
        for (Type baseType : actualTypeArguments) {
            while (resolvedTypes.containsKey(baseType)) {
                baseType = resolvedTypes.get(baseType);
            }
            typeArgumentsAsClasses.add(getClass(baseType));
        }
        return typeArgumentsAsClasses;
    }
  }
Ondrej Bozek
  • 9,501
  • 6
  • 48
  • 66
9

I think there is another elegant solution.

What you want to do is (safely) "pass" the type of the generic type parameter up from the concerete class to the superclass.

If you allow yourself to think of the class type as "metadata" on the class, that suggests the Java method for encoding metadata in at runtime: annotations.

First define a custom annotation along these lines:

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EntityAnnotation {
    Class entityClass();
}

You can then have to add the annotation to your subclass.

@EntityAnnotation(entityClass =  PassedGenericType.class)
public class Subclass<PassedGenericType> {...}

Then you can use this code to get the class type in your base class:

import org.springframework.core.annotation.AnnotationUtils;
.
.
.

private Class getGenericParameterType() {
    final Class aClass = this.getClass();
    EntityAnnotation ne = 
         AnnotationUtils.findAnnotation(aClass, EntityAnnotation.class);

    return ne.entityClass();
}

Some limitations of this approach are:

  1. You specify the generic type (PassedGenericType) in TWO places rather than one which is non-DRY.
  2. This is only possible if you can modify the concrete subclasses.
DaBlick
  • 788
  • 8
  • 18
8

This is my solution:

import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class GenericClass<T extends String> {

  public static void main(String[] args) {
     for (TypeVariable typeParam : GenericClass.class.getTypeParameters()) {
      System.out.println(typeParam.getName());
      for (Type bound : typeParam.getBounds()) {
         System.out.println(bound);
      }
    }
  }
}
Matthias M
  • 8,008
  • 11
  • 67
  • 83
  • 11
    This is not an answer for this question. – Adam Arold Sep 04 '13 at 14:04
  • 1
    My code is not the exact solution for the question. It returns the generic type parameters of the class, but not the actual type of T. But it may be helpful for others who stumple upon the question and are looking for my solution. – Matthias M Jan 24 '14 at 08:30
  • 1
    getClass().getGenericSuperclass() will achieve the same effect. – Gorky Jul 01 '14 at 22:36
6

Here's one way, which I've had to use once or twice:

public abstract class GenericClass<T>{
    public abstract Class<T> getMyType();
}

Along with

public class SpecificClass extends GenericClass<String>{

    @Override
    public Class<String> getMyType(){
        return String.class;
    }
}
PJWeisberg
  • 115
  • 1
  • 3
  • 4
    This technically works, however it doesn't solve the general case, and I think that is what the original poster is after. – ggb667 Nov 05 '13 at 15:02
  • This doesn't deserve to be voted down like is has - the original poster hasn't been explicit. This answer offers a design pattern that *does* work and is easy to implement, provided it is suitable to make the generic class abstract. – VirtualMichael Sep 23 '15 at 04:06
5

Here is working solution!!!

@SuppressWarnings("unchecked")
    private Class<T> getGenericTypeClass() {
        try {
            String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
            Class<?> clazz = Class.forName(className);
            return (Class<T>) clazz;
        } catch (Exception e) {
            throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
        }
    } 

NOTES: Can be used only as superclass
1. Has to be extended with typed class (Child extends Generic<Integer>)
OR

2. Has to be created as anonymous implementation (new Generic<Integer>() {};)

Yaroslav Kovbas
  • 360
  • 3
  • 6
5

You can't. If you add a member variable of type T to the class (you don't even have to initialise it), you could use that to recover the type.

andrewmu
  • 13,259
  • 4
  • 36
  • 37
5

One simple solution for this cab be like below

public class GenericDemo<T>{
    private T type;

    GenericDemo(T t)
    {
        this.type = t;
    }

    public String getType()
    {
        return this.type.getClass().getName();
    }

    public static void main(String[] args)
    {
        GenericDemo<Integer> obj = new  GenericDemo<Integer>(5);
        System.out.println("Type: "+ obj.getType());
    }
}
perror
  • 6,329
  • 16
  • 56
  • 72
Paul92
  • 109
  • 1
  • 7
3

To complete some of the answers here, I had to get the ParametrizedType of MyGenericClass, no matter how high is the hierarchy, with the help of recursion:

private Class<T> getGenericTypeClass() {
        return (Class<T>) (getParametrizedType(getClass())).getActualTypeArguments()[0];
}

private static ParameterizedType getParametrizedType(Class clazz){
    if(clazz.getSuperclass().equals(MyGenericClass.class)){ // check that we are at the top of the hierarchy
        return (ParameterizedType) clazz.getGenericSuperclass();
    } else {
        return getParametrizedType(clazz.getSuperclass());
    }
}
galex
  • 3,219
  • 2
  • 31
  • 46
2

Here is my trick:

public class Main {

    public static void main(String[] args) throws Exception {

        System.out.println(Main.<String> getClazz());

    }

    static <T> Class getClazz(T... param) {

        return param.getClass().getComponentType();
    }

}
HRgiger
  • 2,612
  • 23
  • 35
  • 1
    Note: this **does not work** when `T` is a type variable. In the case that `T` is a type variable, the varargs creates an array of erasure of `T`. See e.g. [http://ideone.com/DIPNwd](http://ideone.com/DIPNwd). – Radiodef Apr 11 '15 at 02:41
  • 1
    This returns "Object" – yahya Apr 24 '15 at 07:19
  • May be you're trying to answer some other question – Khan May 06 '20 at 15:38
2

Here is my solution

public class GenericClass<T>
{
    private Class<T> realType;

    public GenericClass() {
        findTypeArguments(getClass());
    }

    private void findTypeArguments(Type t) {
        if (t instanceof ParameterizedType) {
            Type[] typeArgs = ((ParameterizedType) t).getActualTypeArguments();
            realType = (Class<T>) typeArgs[0];
        } else {
            Class c = (Class) t;
            findTypeArguments(c.getGenericSuperclass());
        }
    }

    public Type getMyType()
    {
        // How do I return the type of T? (your question)
        return realType;
    }
}

No matter how many level does your class hierarchy has, this solution still works, for example:

public class FirstLevelChild<T> extends GenericClass<T> {

}

public class SecondLevelChild extends FirstLevelChild<String> {

}

In this case, getMyType() = java.lang.String

Lin Yu Cheng
  • 565
  • 8
  • 21
  • This is not returning the type of T. It is returning T not java.lang.String besides the code is failing to covert Type to Class – Mohy Eldeen Sep 08 '16 at 17:38
  • Here is a online sample I made. Click compile and execute, then you can get the result. http://www.tutorialspoint.com/compile_java_online.php?PID=0Bw_CjBb95KQMazdtdjA1Z2tlWE0 – Lin Yu Cheng Oct 26 '16 at 00:28
  • Works for me - when WildFly Weld CDI broke an alternative method. – Andre Jul 26 '17 at 21:14
  • I got ```Exception in thread "main" java.lang.NullPointerException at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.findTypeArguments(Main.java:54) at Main$ClassA.(Main.java:43) at Main.main(Main.java:61) ``` – yuyang Mar 20 '19 at 22:25
2
public static final Class<?> getGenericArgument(final Class<?> clazz)
{
    return (Class<?>) ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments()[0];
}
kayz1
  • 6,652
  • 3
  • 48
  • 54
1

Just in case you use store a variable using the generic type you can easily solve this problem adding a getClassType method as follows:

public class Constant<T> {
  private T value;

  @SuppressWarnings("unchecked")
  public Class<T> getClassType () {
    return ((Class<T>) value.getClass());
  }
}

I use the provided class object later to check if it is an instance of a given class, as follows:

Constant<?> constant = ...;
if (constant.getClassType().equals(Integer.class)) {
    Constant<Integer> integerConstant = (Constant<Integer>)constant;
    Integer value = integerConstant.getValue();
    // ...
}
  • 2
    This is problematic, unfortunately. First of all, what if `value` is `null`? Second of all, what if `value` is a subclass of `T`? `Constant c = new Constant(new Integer(0)); Class n = c.getClassType();` returns `Integer.class` when it should return `Number.class`. It would be more correct to return `Class extends T>`. `Integer.class` *is a* `Class extends Number>` but not a `Class`. – Radiodef Apr 11 '15 at 02:30
1

Here is my solution. The examples should explain it. The only requirement is that a subclass must set the generic type, not an object.

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;

public class TypeUtils {

    /*** EXAMPLES ***/

    public static class Class1<A, B, C> {

        public A someA;
        public B someB;
        public C someC;

        public Class<?> getAType() {
            return getTypeParameterType(this.getClass(), Class1.class, 0);
        }

        public Class<?> getCType() {
            return getTypeParameterType(this.getClass(), Class1.class, 2);
        }
    }

    public static class Class2<D, A, B, E, C> extends Class1<A, B, C> {

        public B someB;
        public D someD;
        public E someE;
    }

    public static class Class3<E, C> extends Class2<String, Integer, Double, E, C> {

        public E someE;
    }

    public static class Class4 extends Class3<Boolean, Long> {

    }

    public static void test() throws NoSuchFieldException {

        Class4 class4 = new Class4();
        Class<?> typeA = class4.getAType(); // typeA = Integer
        Class<?> typeC = class4.getCType(); // typeC = Long

        Field fieldSomeA = class4.getClass().getField("someA");
        Class<?> typeSomeA = TypeUtils.getFieldType(class4.getClass(), fieldSomeA); // typeSomeA = Integer

        Field fieldSomeE = class4.getClass().getField("someE");
        Class<?> typeSomeE = TypeUtils.getFieldType(class4.getClass(), fieldSomeE); // typeSomeE = Boolean


    }

    /*** UTILS ***/

    public static Class<?> getTypeVariableType(Class<?> subClass, TypeVariable<?> typeVariable) {
        Map<TypeVariable<?>, Type> subMap = new HashMap<>();
        Class<?> superClass;
        while ((superClass = subClass.getSuperclass()) != null) {

            Map<TypeVariable<?>, Type> superMap = new HashMap<>();
            Type superGeneric = subClass.getGenericSuperclass();
            if (superGeneric instanceof ParameterizedType) {

                TypeVariable<?>[] typeParams = superClass.getTypeParameters();
                Type[] actualTypeArgs = ((ParameterizedType) superGeneric).getActualTypeArguments();

                for (int i = 0; i < typeParams.length; i++) {
                    Type actualType = actualTypeArgs[i];
                    if (actualType instanceof TypeVariable) {
                        actualType = subMap.get(actualType);
                    }
                    if (typeVariable == typeParams[i]) return (Class<?>) actualType;
                    superMap.put(typeParams[i], actualType);
                }
            }
            subClass = superClass;
            subMap = superMap;
        }
        return null;
    }

    public static Class<?> getTypeParameterType(Class<?> subClass, Class<?> superClass, int typeParameterIndex) {
        return TypeUtils.getTypeVariableType(subClass, superClass.getTypeParameters()[typeParameterIndex]);
    }

    public static Class<?> getFieldType(Class<?> clazz, AccessibleObject element) {
        Class<?> type = null;
        Type genericType = null;

        if (element instanceof Field) {
            type = ((Field) element).getType();
            genericType = ((Field) element).getGenericType();
        } else if (element instanceof Method) {
            type = ((Method) element).getReturnType();
            genericType = ((Method) element).getGenericReturnType();
        }

        if (genericType instanceof TypeVariable) {
            Class<?> typeVariableType = TypeUtils.getTypeVariableType(clazz, (TypeVariable) genericType);
            if (typeVariableType != null) {
                type = typeVariableType;
            }
        }

        return type;
    }

}
PetermaxX
  • 19
  • 1
  • 3
0

If you have a class like:

public class GenericClass<T> {
    private T data;
}

with T variable, then you can print T name:

System.out.println(data.getClass().getSimpleName()); // "String", "Integer", etc.
CoolMind
  • 16,738
  • 10
  • 131
  • 165
0

This was inspired by Pablo's and CoolMind's answers. Occasionally I have also used the technique from kayz1's answer (expressed in many other answers as well), and I believe it is a decent and reliable way to do what the OP asked.

I chose to define this as an interface (similar to PJWeisberg) first because I have existing types that would benefit from this functionality, particularly a heterogeneous generic union type:

public interface IGenericType<T>
{
    Class<T> getGenericTypeParameterType();
}

Where my simple implementation in a generic anonymous interface implementation looks like the following:

//Passed into the generic value generator function: toStore
//This value name is a field in the enclosing class.
//IUnionTypeValue<T> is a generic interface that extends IGenericType<T>
value = new IUnionTypeValue<T>() {
    ...
    private T storedValue = toStore;
    ...
    
    @SuppressWarnings("unchecked")
    @Override
    public Class<T> getGenericTypeParameterType()
    {
        return (Class<T>) storedValue.getClass();
    }
}

I imagine this could be also implemented by being built with a class definition object as the source, that's just a separate use-case. I think the key is as many other answers have stated, in one way or another, you need to get the type information at runtime to have it available at runtime; the objects themselves maintain their type, but erasure (also as others have said, with appropriate references) causes any enclosing/container types to lose that type information.

jhyry-gcpud
  • 95
  • 2
  • 7
-1

I did the same as @Moesio Above but in Kotlin it could be done this way:

class A<T : SomeClass>() {

    var someClassType : T

    init(){
    this.someClassType = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<T>
    }

}
Bonestack
  • 85
  • 6
-4

It might be useful to someone. You can Use java.lang.ref.WeakReference; this way:

class SomeClass<N>{
  WeakReference<N> variableToGetTypeFrom;

  N getType(){
    return variableToGetTypeFrom.get();
  }
}
TheLetch
  • 165
  • 2
  • 11
  • How's this class supposed to be used? Why `WeakReference`? Please provide some explanation with your answer, not just some code. – Abhijit Sarkar Oct 26 '18 at 22:39
  • So if you have a `SomeClass` you can instantiate `SomeClass` and call `getType` on that instance and have the runtime to be `MyClass`. – TheLetch Oct 26 '18 at 23:17
  • Sure, but why `WeakReference`? What you said is not different from most of the other answers. – Abhijit Sarkar Oct 27 '18 at 03:02
  • First my approach is shorter(less code), second the Weak references do not prevent their referents from being made finalizable, and as far as I know it doesn't use reflection, thus it's fast – TheLetch Oct 28 '18 at 00:51
  • This does not get the type of anything, this returns an object of that type, which, fyi, you can do with literally any kind of wrapper (`AtomicReference`, `List`, `Set`). – Frontear Sep 03 '19 at 05:34
-5

I found this to be a simple understandable and easily explainable solution

public class GenericClass<T> {

    private Class classForT(T...t) {
        return t.getClass().getComponentType();
    }

    public static void main(String[] args) {
        GenericClass<String> g = new GenericClass<String>();

        System.out.println(g.classForT());
        System.out.println(String.class);
    }
}