Get generic type of class at runtime

2018-12-31 00:34发布

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.

23条回答
深知你不懂我心
2楼-- · 2018-12-31 00:51

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.
查看更多
大哥的爱人
3楼-- · 2018-12-31 00:52

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);
      }
    }
  }
}
查看更多
只若初见
4楼-- · 2018-12-31 00:56

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());
    }
}
查看更多
残风、尘缘若梦
5楼-- · 2018-12-31 00:57

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>() {};)

查看更多
柔情千种
6楼-- · 2018-12-31 01:02

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();
    }
}
查看更多
骚的不知所云
7楼-- · 2018-12-31 01:02

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;
    }
}
查看更多
登录 后发表回答