获取通用类的.class对象

时间:2019-12-06 10:02:32

标签: java generics

我想保存一个通用值的类型,因为在运行时无法获取它:

public class A<T> {
    private final Class<T> genericType;
    public A(Class<T> genericType) {
        this.genericType = genericType;
    }

    public Class getGenericType() {
        return genericType;
    }
}

要立即创建子类,请按以下方式使用它:

public class B extends A<String> {
    public B() {
        super(String.class);
    }
}

请注意,super()的参数类型与A的泛型类型匹配(通过编译时机检查)。 很好但是,如果我想将其与Map一起使用,则无法获得正确的类对象:

public class C extends A<Map<String, String>> {
    public C() {
        super(Map.class); // does not match Map<String,String>
        super(Map<String,String>.class) // no valid java expression, i dont know what 
    }
}

那么有人能帮我摆脱这种痛苦吗? 我目前能做的最好的就是放弃强力输入A:

public class A<T> {
    // old: private final Class<T> genericType;
    private final Class genericType;  // note the missing generic
    public A(Class genericType) {     // here as well
        this.genericType = genericType;
    }

    public Class getGenericType() {
        return genericType;
    }
}

2 个答案:

答案 0 :(得分:3)

我不确定这是否满足您的要求,但是您可以执行类似波纹管的操作,请参见How to get the class of a field of type T?

<b-modal
    v-bind="$attrs"
    title="Add new customer"
    @ok="addCustomer"
>

<form ref="form" @submit.stop.prevent>
    <b-form-group label="Account Name" label-for="account_name-input">
        <b-form-input
                id="account_name-input"
                v-model="account_name"
                v-model.trim="$v.account_name.$model"
                :class="{
'is-invalid':$v.account_name.$error, 'is-valid':!$v.account_name.$invalid}"
        ></b-form-input>
        <div class="invalid-feedback">
            <span v-if="!$v.account_name.required">This field is required!</span>
        </div>
    </b-form-group>
</form>

addCustomer() {
    if (this.$v.$invalid) {
        console.log('Error');
    }else{
        console.log("Succes");
        let newCustomer = {
            account_name: this.account_name,
        };

        ...code...
    }
},

validations: {
    account_name: {
        required
    },
}

这将得到类似的输出

import java.lang.reflect.*;
import java.util.*;


public class GenericTypeTest{

     public static void main(String []args){
        B b = new B();
        System.out.println("B is a " + b.getGenericType());
        C c = new C();
        System.out.println("C is a " + c.getGenericType());
     }
}


class A<T> {
      public Class getGenericType() {
          Object genericType =  ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
           if(genericType instanceof ParameterizedType){
               genericType = ((ParameterizedType)genericType).getRawType();
           }
        return (Class<T>) genericType;
    }
}



class B extends A<String> {
}

class C extends A<Map<String,String>> {
}

答案 1 :(得分:0)

在运行时只有一个Class对象代表Map,您可以通过评估Map.class来获得。在运行时,没有单独的Class对象表示Map<String, String>Map<Integer, Integer>或其他对象。如果您只想取Map.class(通常类型为Class<Map>)并将其强行插入Class<Map<String, String>>,则可以通过一些未经检查的强制转换来实现:

super((Class<Map<String, String>>)(Class<?>)Map.class);

但是这是否可以满足您的期望,取决于您对未显示的类型Class<T>genericType的变量的期望。例如,如果您将使用其.isInstance()方法在运行时检查对象是否为T的实例,请知道由于我们在运行时不知道对象的通用类型参数,因此仅能够检查对象的原始类型,而不能检查其类型参数。这就是为什么您可以foo instanceof Mapfoo instanceof Map<?>但不能foo instanceof Map<String, String>的原因。

或者,也许您想在运行时使用其.cast()方法对对象进行类型检查,如果对象不是Class类的实例,通常会引发异常,如果是,它将返回对象,但其编译时类型为T。但是在这里,同样,您不能在运行时检查对象是否为参数化类型的实例,例如Map<String, String>;您只能检查它是否为Map。因此,通过这种方式允许您在没有警告的情况下获取类型为T的结果可能是不安全的,因为您会得到类型为Map<String, String>的编译时表达式,但实际上可能是Map<Integer, Integer>。这就是(Map<String, String>)foo之类的未经检查的强制类型转换导致未经检查的强制转换警告的相同原因。这是不安全的,并且可能在代码的其他地方引起意外问题。