Java 获取没有扩展的通用类型

Java Get Generic Type without extends

我有一个像这样的简单界面。

public interface EntityClass
{    
   public void setId(final Integer id);    
   public Integer getId();    
}

和一个class

public Student implements EntityClass{}

但是这段代码给我错误 我想知道 Generic Type

public class MyGenericType<T extends EntityClass>
{
     private final Class<? extends EntityClass>genericClazz;
     public MyGenericType()
     {   
        genericClazz=(Class<? extends EntityClass>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        return;
     }        
 }

稍后我尝试这样的代码

public static void main(String[] args) 
{        
     final MyGenericType<Student>action = new MyGenericType<>();
}

但是它抛出

Exception in thread "main" java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType

这段代码我一直在使用它但是从 subclass 扩展但我不想我的 GenericType 从任何 class.

扩展

我该怎么做才能从此代码中获取 Student 类型。

final MyGenericType<Student>action = new MyGenericType<>();

因为我需要得到一个Hibernate namedQuery.

1) 没有不继承任何class的东西,每一样东西都是对象class的扩展,所以即使你不指定任何东西,默认情况下它将扩展对象。

2) 在泛型class中有两种获取运行时类型的方法,可以在变量上使用getClass,或者在构造函数或方法中传入class。 示例代码:

方法一(尽可能推荐):

public class MyGenericType<T extends EntityClass>
{
     public <T extends EntityClass> void someMethod(final T someVar)
     {   
         Class c = someVar.getClass();
     }        
 }

方法二(如果需要在构建时确定,只能这样):

public class MyGenericType<T extends EntityClass>
{
     private final Class<? extends EntityClass>genericClazz;
     public MyGenericType(Class t)
     {   
         genericClazz = t;
         return;
     }        
 }

由于擦除,您无法获取有关泛型类型的信息,简而言之,这意味着Java编译器不保留泛型类型信息关于生成的字节码中的实际实例。

但是,编译器不会去除实际实例的superclass的泛型类型信息。因此,您可以在具有通用类型参数的 class 的 descendant 上使用 (ParameterizedType) this.getClass().getGenericSuperclass(),为此,您需要使用 extends 关键词:

public interface EntityClass {
    public void setId(final Integer id);

    public Integer getId();
}

public class Student
    implements EntityClass {

    // getters and setters
}

public abstract class MyGenericType<T extends EntityClass> {

    private final Class<T> genericClazz;

    @SuppressWarnings("unchecked")
    public MyGenericType() {
        this.genericClazz = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass())
            .getActualTypeArguments()[0];
    }

    protected Class<T> getGenericClazz() {
        return this.genericClazz;
    }

}

public class MyStudentType // no way to avoid extending a generic type
    extends MyGenericType<Student> {

    @Override
    public String toString() {
        return this.getGenericClazz().getSimpleName();
    }
}

public class Sample {

    public static void main(String[] args) {
        final MyStudentType action = new MyStudentType();
        System.out.println(action); // Student
    }
}

关于 MyGenericType<T> class' 构造函数中此转换的评论:

genericClazz = (Class<? extends EntityClass>)...

由于 T 被声明为从 EntityClass 扩展而来,您不需要使用通配符。仅使用 T 就足够了:

genericClazz = (Class<T>)...

关于您得到的 ClassCastException,那是因为在您的示例中,MyGenericType 没有通用的 superclass(实际上,它没有任何 super class,但 Object 除外,它不是 ParameterizedType。因此,当您使用此转换时:(ParameterizedType) getClass().getGenericSuperclass(),您将得到 ClassCastException


编辑:

我忘了你问的是如何做到这一点 不必从任何 class 扩展。一种方法是在构造函数中传递泛型类型:

public class MyGenericType<T extends EntityClass> {

    private final Class<T> genericClazz;

    public MyGenericType(Class<T> clazz) {
        this.genericClazz = clazz;
    }

    @Override
    public String toString() {
        return this.genericClazz.getSimpleName();
    }
}

然后:

public class Sample {

    public static void main(String[] args) {
        final MyGenericType<Student> action = new MyGenericType<>(Student.class);
        System.out.println(action); // Student
    }
}

编辑 2:

另一种方法是使您的 MyGenericType class abstract 并让 subclasses return 成为通用类型。这可能是由泛型强制执行的,因此如果 subclass 尝试 return 错误的类型,它会得到一个编译错误:

public abstract class MyGenericType<T extends EntityClass> {

    protected abstract Class<T> getGenericType();

    @Override
    public String toString() {
        return this.getGenericType().getSimpleName();
    }
}

public class MyStudentType 
    extends MyGenericType<Student> {

    @Override
    protected Class<Student> getGenericType() {
        return Student.class;
    }
}

然后:

public class Sample {

    public static void main(String[] args) {
        final MyStudentType action = new MyStudentType();
        System.out.println(action); // Student
    }
}