Java获取Generic Type而不扩展

时间:2015-03-13 12:43:26

标签: java hibernate generics

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

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

和一个班级

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

这段代码我一直在使用它,但是从子类扩展但我不希望我的GenericType扩展到任何类。

如何从此代码中获取Student类型。

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

因为我需要获得Hibernate namedQuery.

2 个答案:

答案 0 :(得分:1)

1)没有不继承任何类的东西,每个东西都是Object类的扩展,所以即使你没有指定任何东西,默认它也会扩展Object。

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

方法1(如果可能,首选):

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

方法2(如果你需要在施工时确定,这是唯一的方法):

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

答案 1 :(得分:1)

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

但是,编译器不会删除实际实例的超类的泛型类型信息。因此,您可以在具有泛型类型参数的类的后代上使用(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>课程中的演员阵容的一条评论&#39;构造:

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

由于T声明从EntityClass延伸,因此您不需要使用通配符。仅使用T就足够了:

genericClazz = (Class<T>)...

关于您获得的ClassCastException,因为在您的示例中,MyGenericType没有通用的超类(实际上,它并没有有Object之外的任何超类,不是ParameterizedType。所以,当你使用这个演员:(ParameterizedType) getClass().getGenericSuperclass()时,你得到ClassCastException。< / p>


修改

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

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:

另一种方法是创建MyGenericTypeabstract并让子类返回泛型类型。这可能由泛型强制执行,因此如果子类尝试返回错误的类型,则会出现编译错误:

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
    }
}