【问题标题】:How can I determine the type of a generic field in Java?如何确定 Java 中泛型字段的类型?
【发布时间】:2009-12-08 17:00:07
【问题描述】:

我一直在尝试确定类中字段的类型。我已经看过所有的内省方法,但还没有完全弄清楚如何去做。这将用于从 java 类生成 xml/json。我在这里查看了一些问题,但没有找到我真正需要的。

例子:

class Person {
    public final String name;
    public final List<Person> children;
}

当我编组这个对象时,我需要知道chidren 字段是Person 类型的对象列表,所以我可以正确编组它。

我试过了

for (Field field : Person.class.getDeclaredFields()) {
    System.out.format("Type: %s%n", field.getType());
}

但这只会告诉我这是List,而不是Persons 中的List

谢谢

【问题讨论】:

  • 列表 ?除非我没有抓住重点。

标签: java generics reflection types introspection


【解决方案1】:

查看 Java 教程 Trail: The Reflection API 中的 Obtaining Field Types

基本上,您需要做的是获取您班级的所有java.lang.reflect.Field并在每个人上调用Field#getType()(检查下面的编辑)。要获取所有对象字段,包括公共、受保护、包和私有访问字段,只需使用Class.getDeclaredFields()。像这样的:

for (Field field : Person.class.getDeclaredFields()) {
    System.out.format("Type: %s%n", field.getType());
    System.out.format("GenericType: %s%n", field.getGenericType());
}

编辑:正如wowest在评论中指出的那样,您实际上需要调用Field#getGenericType(),检查返回的Type是否是ParameterizedType,然后相应地获取参数.使用ParameterizedType#getRawType()ParameterizedType#getActualTypeArgument() 分别获取ParameterizedType 的类型参数的原始类型和数组。下面的代码演示了这一点:

for (Field field : Person.class.getDeclaredFields()) {
    System.out.print("Field: " + field.getName() + " - ");
    Type type = field.getGenericType();
    if (type instanceof ParameterizedType) {
        ParameterizedType pType = (ParameterizedType)type;
        System.out.print("Raw type: " + pType.getRawType() + " - ");
        System.out.println("Type args: " + pType.getActualTypeArguments()[0]);
    } else {
        System.out.println("Type: " + field.getType());
    }
}

并且会输出:

Field: name - Type: class java.lang.String
Field: children - Raw type: interface java.util.List - Type args: class foo.Person

【讨论】:

  • 帕斯卡——你非常接近。你想要 Type type = Field.getGenericType();然后检查它是否是ParameterizedType,然后获取参数。这最终变成了一个兔子洞——提问者需要定义限制或准备编写一些漂亮的代码。
  • 感谢 wowest,这正是我需要与 ParameterizedType.getRawType 和 ParameterizedType.getActualArguments 结合使用的。
  • 我不知道如何将您的评论标记为正确答案,所以我只回答我自己的问题,以便发布示例
  • @Juan Mendes,您应该会在每个答案的左侧看到一个勾号图标,在投票编号旁边,只需单击属于正确答案的那个,它就会变成绿色。
  • 我知道我可以将此答案标记为正确答案。然而,直到 Pascal 编辑它以同意 wowest 的评论之前,它是不正确的。无论如何,我在下面列出的示例包含了我需要的所有信息,但在这么多人帮助我之后,我不想将自己的答案标记为正确答案。 Pascal 的示例仍然缺少关键方法(ParameterizedType.getRawType 和 ParameterizedType.getActualArguments?)。 Pascal,您能否编辑示例以显示正在使用的这两种方法?
【解决方案2】:

这是一个回答我问题的例子

class Person {
  public final String name;
  public final List<Person> children;  
}

//in main
Field[] fields = Person.class.getDeclaredFields();
for (Field field : fields) {
  Type type = field.getGenericType();
  System.out.println("field name: " + field.getName());
  if (type instanceof ParameterizedType) {
    ParameterizedType ptype = (ParameterizedType) type;
    ptype.getRawType();
    System.out.println("-raw type:" + ptype.getRawType());
    System.out.println("-type arg: " + ptype.getActualTypeArguments()[0]);
  } else {
    System.out.println("-field type: " + field.getType());
  }
}

这个输出

字段名称:名称 -字段类型:类 java.lang.String 字段名称:儿童 -原始类型:接口 java.util.List -type arg:com.blah.Person 类

【讨论】:

    【解决方案3】:

    我还没有找到任何通过继承层确定通用字段类型的框架,所以我写了一些方法:

    这个逻辑通过字段信息和当前对象类来判断类型。

    清单 1 - 逻辑:

    public static Class<?> determineType(Field field, Object object) {
        Class<?> type = object.getClass();
        return (Class<?>) getType(type, field).type;
    }
    
    protected static class TypeInfo {
        Type type;
        Type name;
    
        public TypeInfo(Type type, Type name) {
            this.type = type;
            this.name = name;
        }
    
    }
    
    private static TypeInfo getType(Class<?> clazz, Field field) {
        TypeInfo type = new TypeInfo(null, null);
        if (field.getGenericType() instanceof TypeVariable<?>) {
            TypeVariable<?> genericTyp = (TypeVariable<?>) field.getGenericType();
            Class<?> superClazz = clazz.getSuperclass();
    
            if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
                ParameterizedType paramType = (ParameterizedType) clazz.getGenericSuperclass();
                TypeVariable<?>[] superTypeParameters = superClazz.getTypeParameters();
                if (!Object.class.equals(paramType)) {
                    if (field.getDeclaringClass().equals(superClazz)) {
                        // this is the root class an starting point for this search
                        type.name = genericTyp;
                        type.type = null;
                    } else {
                        type = getType(superClazz, field);
                    }
                }
                if (type.type == null || type.type instanceof TypeVariable<?>) {
                    // lookup if type is not found or type needs a lookup in current concrete class
                    for (int j = 0; j < superClazz.getTypeParameters().length; ++j) {
                        TypeVariable<?> superTypeParam = superTypeParameters[j];
                        if (type.name.equals(superTypeParam)) {
                            type.type = paramType.getActualTypeArguments()[j];
                            Type[] typeParameters = clazz.getTypeParameters();
                            if (typeParameters.length > 0) {
                                for (Type typeParam : typeParameters) {
                                    TypeVariable<?> objectOfComparison = superTypeParam;
                                    if(type.type instanceof TypeVariable<?>) {
                                        objectOfComparison = (TypeVariable<?>)type.type;
                                    }
                                    if (objectOfComparison.getName().equals(((TypeVariable<?>) typeParam).getName())) {
                                        type.name = typeParam;
                                        break;
                                    }
                                }
                            }
                            break;
                        }
                    }
                }
            }
        } else {
            type.type = field.getGenericType();
        }
    
        return type;
    }
    

    清单 2 - 样本/测试:

    class GenericSuperClass<E, T, A> {
        T t;
        E e;
        A a;
        BigDecimal b;
    }
    
    class GenericDefinition extends GenericSuperClass<Integer, Integer, Integer> {
    
    }
    
    @Test
    public void testSimpleInheritanceTypeDetermination() {
        GenericDefinition gd = new GenericDefinition();
        Field field = ReflectionUtils.getField(gd, "t");
        Class<?> clazz = ReflectionUtils.determineType(field, gd);
        Assert.assertEquals(clazz, Integer.class);
        field = ReflectionUtils.getField(gd, "b");
        clazz = ReflectionUtils.determineType(field, gd);
        Assert.assertEquals(clazz, BigDecimal.class);
    }
    
    class MiddleClass<A, E> extends GenericSuperClass<E, Integer, A> { }
    
    // T = Integer, E = String, A = Double
    class SimpleTopClass extends MiddleClass<Double, String> { }
    
    @Test
    public void testSimple2StageInheritanceTypeDetermination() {
        SimpleTopClass stc = new SimpleTopClass();
        Field field = ReflectionUtils.getField(stc, "t");
        Class<?> clazz = ReflectionUtils.determineType(field, stc);
        Assert.assertEquals(clazz, Integer.class);
        field = ReflectionUtils.getField(stc, "e");
        clazz = ReflectionUtils.determineType(field, stc);
        Assert.assertEquals(clazz, String.class);
        field = ReflectionUtils.getField(stc, "a");
        clazz = ReflectionUtils.determineType(field, stc);
        Assert.assertEquals(clazz, Double.class);
    }
    
    class TopMiddleClass<A> extends MiddleClass<A, Double> { }
    
    // T = Integer, E = Double, A = Float
    class ComplexTopClass extends TopMiddleClass<Float> {}
    
    @Test void testComplexInheritanceTypDetermination() {
        ComplexTopClass ctc = new ComplexTopClass();
        Field field = ReflectionUtils.getField(ctc, "t");
        Class<?> clazz = ReflectionUtils.determineType(field, ctc);
        Assert.assertEquals(clazz, Integer.class);
        field = ReflectionUtils.getField(ctc, "e");
        clazz = ReflectionUtils.determineType(field, ctc);
        Assert.assertEquals(clazz, Double.class);
        field = ReflectionUtils.getField(ctc, "a");
        clazz = ReflectionUtils.determineType(field, ctc);
        Assert.assertEquals(clazz, Float.class);
    }
    
    class ConfusingClass<A, E> extends MiddleClass<E, A> {}
    // T = Integer, E = Double, A = Float ; this class should map between a and e
    class TopConfusingClass extends ConfusingClass<Double, Float> {}
    
    @Test
    public void testConfusingNamingConvetionWithInheritance() {
        TopConfusingClass tcc = new TopConfusingClass();
        Field field = ReflectionUtils.getField(tcc, "t");
        Class<?> clazz = ReflectionUtils.determineType(field, tcc);
        Assert.assertEquals(clazz, Integer.class);
        field = ReflectionUtils.getField(tcc, "e");
        clazz = ReflectionUtils.determineType(field, tcc);
        Assert.assertEquals(clazz, Double.class);
        field = ReflectionUtils.getField(tcc, "a");
        clazz = ReflectionUtils.determineType(field, tcc);
        Assert.assertEquals(clazz, Float.class);
        field = ReflectionUtils.getField(tcc, "b");
        clazz = ReflectionUtils.determineType(field, tcc);
        Assert.assertEquals(clazz, BigDecimal.class);
    }
    
    class Pojo {
        Byte z;
    }
    
    @Test
    public void testPojoDetermineType() {
        Pojo pojo = new Pojo();
        Field field = ReflectionUtils.getField(pojo, "z");
        Class<?> clazz = ReflectionUtils.determineType(field, pojo);
        Assert.assertEquals(clazz, Byte.class);
    }
    

    我期待听到您的反馈!

    【讨论】:

    • 谢谢!这种方法帮助很大。我建议添加检查 type.type 是否是ParameterizedTypeImpl 的实例,在这种情况下.getRawType() 方法会产生该类型。当类型为List&lt;Double&gt; 时,这将获取List。 (否则可能会得到ParameterizedTypeImpl cannot be cast to java.lang.Class
    【解决方案4】:

    拿着这个sn-p:

     for (Field field : Person.class.getFields()) {
            System.out.println(field.getType());
     }
    

    关键类是Field

    【讨论】:

    • 只有Class.getFields 的公共字段(包括静态)。也将是擦除类型。
    • 那我误解了问题
    【解决方案5】:

    这是我的看法。它不能处理所有可能的情况(并且肯定有一些错误),但它确实处理了到目前为止我的代码中出现的所有情况。这包括这些声明,这对于许多用例来说应该是一个好的开始:

      private int                                                primitiveField1;
    
      private Object                                             field1;
      private List<Integer>                                      field2;
      private Map<Integer, String>                               field3;
      private Map<? extends String, List<Map<Class<?>, Object>>> field4;
    
      private char[]                                             array1;
      private Character[]                                        array2;
      private Class<? extends Integer>[]                         array3;
      private List<Integer>[]                                    array4;
    
      private InnerClass<String>                                 innerClass;
    

    实施:

      public static String getDeclaration(Field field) {
        return getDeclaration(field.getGenericType());
      }
    
      private static String getDeclaration(Type genericType) {
        if(genericType instanceof ParameterizedType) {
          // types with parameters
          ParameterizedType parameterizedType = (ParameterizedType) genericType;
          String declaration = parameterizedType.getRawType().getTypeName();
          declaration += "<";
    
          Type[] typeArgs = parameterizedType.getActualTypeArguments();
    
          for(int i = 0; i < typeArgs.length; i++) {
            Type typeArg = typeArgs[i];
    
            if(i > 0) {
              declaration += ", ";
            }
    
            // note: recursive call
            declaration += getDeclaration(typeArg);
          }
    
          declaration += ">";
          declaration = declaration.replace('$', '.');
          return declaration;
        }
        else if(genericType instanceof Class<?>) {
          Class<?> clazz = (Class<?>) genericType;
    
          if(clazz.isArray()) {
            // arrays
            return clazz.getComponentType().getCanonicalName() + "[]";
          }
          else {
            // primitive and types without parameters (normal/standard types)
            return clazz.getCanonicalName();
          }
        }
        else {
          // e.g. WildcardTypeImpl (Class<? extends Integer>)
          return genericType.getTypeName();
        }
      }
    

    【讨论】:

    • 你能评论一下你能做什么而 javaBeCool 不能吗?我想知道两者的混合是否是处理递归泛型和继承所需要的。见stackoverflow.com/a/19363555/227299
    • @JuanMendes javaBeCool 似乎解决了一个不同的用例。我的答案是将字段声明作为字符串获取,我在代码生成项目中使用它。我原来的问题被标记为这个问题的重复 - 这就是我在此处发布的原因 (stackoverflow.com/q/45083186/1124509)。
    【解决方案6】:

    正如 dfa 指出的那样,您可以使用 java.lang.reflect.Field.getType 获取已擦除类型。您可以使用Field.getGenericType 获得泛型类型(可能有通配符和绑定的泛型参数以及各种疯狂)。您可以通过Class.getDeclaredFields 获取字段(Class.getFields 将为您提供公共字段(包括 supertpye 的字段)- 毫无意义)。要获取基本类型字段,请通过Class.getSuperclass。请注意检查来自 Field.getModifiers 的修饰符 - 静态字段可能不会对您感兴趣。

    【讨论】:

      【解决方案7】:

      field.getGenericType() 方法返回对Type 接口的引用。 真正的类型可能是 TypeVariableGenericArrayTypeParameterizedTypeClass 或其他我目前不知道的实例。

      需要不同的方法来检索字段的实际类型。

      这是我以 TypeFieldTreeNode 对象树的形式获取公共字段信息的解决方案。

      public class TypeFieldTreeNode {
          public String fieldName;
          public String typeSimpleName;
          public String typeCanonicalName;
          public String typeGenericName;
          public List<TypeFieldTreeNode> children;
      
          public TypeFieldTreeNode(String fieldName, String typeSimpleName, String typeCanonicalName, String genericTypeName) {
              this.fieldName = fieldName;
              this.typeSimpleName = typeSimpleName;
              this.typeCanonicalName = typeCanonicalName;
              this.typeGenericName = genericTypeName;
              this.children = new ArrayList<>();
          }
      }
      

      主要方法:

      private List<TypeFieldTreeNode> getTypeFields(Class<?> clazz, Type genericType,
                                                    Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
          if(clazz == null) { 
              return Collections.emptyList();
          }
      
          List<Field> fields = Arrays.stream(clazz.getDeclaredFields())
                  .filter(f -> Modifier.isPublic(f.getModifiers()) && !Modifier.isFinal(f.getModifiers()))
                  .collect(Collectors.toList());
      
          List<TypeFieldTreeNode> result = new ArrayList<>();
          Map<TypeVariable<?>, Type> classArgumentsMap = mapTypeActualClassArguments(
                  clazz, genericType, actualClassArguments);
      
          for(Field field : fields) {
              result.add(getClassFieldData(field, classArgumentsMap));
          }
      
          if(clazz.getSuperclass() != null) {
              List<TypeFieldTreeNode> superClassFields =
                      getTypeFields(clazz.getSuperclass(), clazz.getGenericSuperclass(), classArgumentsMap);
              result.addAll(superClassFields);
          }
          return result;
      }
      

      接下来是一个核心方法的列表,它将泛型参数的 TypeVariable 类型的元数据与泛型参数的实际类型绑定。 当泛型参数的类型是 TypeVariable 的实例时,方法使用前面获得的映射来恢复该泛型参数的实际类型:

      private Map<TypeVariable<?>, Type> mapTypeActualClassArguments(Class<?> clazz, Type genericType,
                                                                         Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
              if(!(genericType instanceof ParameterizedType)) {
                  return Collections.emptyMap();
              }
      
              Map<TypeVariable<?>, Type> result = new HashMap<>();
              Type[] actualTypeParametersTypes = ((ParameterizedType) genericType).getActualTypeArguments();
              TypeVariable<?>[] classTypeParameters = clazz.getTypeParameters();
      
              for (int i = 0; i < classTypeParameters.length; i++) {
                  if(actualTypeParametersTypes[i] instanceof TypeVariable<?>) {
                      TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) actualTypeParametersTypes[i];
      
                      if(actualClassArguments.containsKey(fieldTypeVariable))
                          actualTypeParametersTypes[i] = actualClassArguments.get(fieldTypeVariable);
                      else
                          throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found",
                                  classTypeParameters[i].getName(), genericType.getTypeName()));
                  }
                  result.put(classTypeParameters[i], actualTypeParametersTypes[i]);
              }
      
              return result;
          }
      

      获取有关字段的数据以及属于该字段类型的类的所有可用字段:

      private TypeFieldTreeNode getClassFieldData(Field field, 
                                                  Map<TypeVariable<?>, Type> actualClassArguments) throws Exception {
          Class<?> fieldClass = field.getType();
          Type fieldGenericType = field.getGenericType();
          TypeFieldTreeNode result = null;
      
          // if type of the field is a generic parameter of the class containing the field
          if(fieldGenericType instanceof TypeVariable<?>) {
              Type actualFieldType = null;
              Class<?> actualFieldClass = null;
              Map<TypeVariable<?>, Type> fieldTypeActualClassArguments = new HashMap<>();
              TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) fieldGenericType;
      
              if(actualClassArguments.containsKey(fieldTypeVariable))
                  actualFieldType = actualClassArguments.get(fieldTypeVariable);
              else
                  throw new Exception(String.format("For a field %s of type %s from class %s, the corresponding actual type of generic parameter was not found",
                          field.getName(), fieldGenericType.getTypeName(), field.getDeclaringClass().getCanonicalName()));
      
              // for example, field "myField2" of class MyClass2<MyClass<Integer>> where:
              // public class MyClass2<T> { public T myField2; }
              // public class MyClass<T> { public T myField; }
              if(actualFieldType instanceof ParameterizedType) {
                  actualFieldClass = (Class<?>)((ParameterizedType) actualFieldType).getRawType();
                  result = new TypeFieldTreeNode(field.getName(), actualFieldClass.getSimpleName(),
                          actualFieldClass.getCanonicalName(), actualFieldType.getTypeName());
      
                  fieldTypeActualClassArguments = mapTypeActualClassArguments(actualFieldClass, actualFieldType, actualClassArguments);
              }
              // for example, field "myField" of class MyClass<Integer> where:
              // public class MyClass<T> { public T myField; }
              else {
                  actualFieldClass = (Class<?>) actualFieldType;
                  result = new TypeFieldTreeNode(field.getName(), actualFieldClass.getSimpleName(),
                          actualFieldClass.getCanonicalName(), "");
              }
      
              List<Field> childFields = Arrays.stream(actualFieldClass.getFields())
                      .filter(f -> !Modifier.isFinal(f.getModifiers()))
                      .collect(Collectors.toList());
              for (Field childField : childFields) {
                  result.children.add(getClassFieldData(childField, fieldTypeActualClassArguments));
              }
          }
          // if the field is an array and the type of the elements of the array is a generic parameter of the class containing the field
          // for example, field "myField" of class MyClass<Integer> where:
          // public class MyClass<T> { public T[] myField; }
          else if(fieldGenericType instanceof GenericArrayType) {
              Type genericComponentType = ((GenericArrayType) fieldGenericType).getGenericComponentType();
              if(genericComponentType instanceof TypeVariable<?>) {
                  if(actualClassArguments.containsKey(genericComponentType)) {
                      Type actualArrayComponentType = actualClassArguments.get(genericComponentType);
                      assert !(actualArrayComponentType instanceof ParameterizedType);
                      Class<?> actualArrayClass = (Class<?>) actualArrayComponentType;
                      result = new TypeFieldTreeNode(field.getName(), actualArrayClass.getSimpleName() + "[]",
                              actualArrayClass.getCanonicalName() + "[]", "");
                  }
                  else
                      throw new Exception(String.format("For a field %s of type %s from class %s, the corresponding actual type of generic parameter was not found",
                              field.getName(), fieldGenericType.getTypeName(), field.getDeclaringClass().getCanonicalName()));
              }
              else
                  throw new Exception(String.format("Unknown array genericComponentType: %s", genericComponentType.getClass().getCanonicalName()));
          }
          else {
              result = new TypeFieldTreeNode(field.getName(), fieldClass.getSimpleName(), fieldClass.getCanonicalName(), "");
              Map<TypeVariable<?>, Type> fieldTypeActualClassArguments = new HashMap<>();
      
              // for example, field "myField2" of class MyClass2<Integer> where:
              // public class MyClass2<T> { public MyClass<T> myField2; }
              // public class MyClass<T> { public T myField; }
              if(fieldGenericType instanceof ParameterizedType) {
      
                  // custom generic type name creator for situations when actual type arguments can be of type TypeVariable
                  result.typeGenericName = getGenericTypeName((ParameterizedType)fieldGenericType, actualClassArguments);
                  fieldTypeActualClassArguments = mapTypeActualClassArguments(fieldClass, fieldGenericType, actualClassArguments);
              }
      
              List<Field> childFields = Arrays.stream(fieldClass.getFields()).filter(f -> !Modifier.isFinal(f.getModifiers()))
                      .collect(Collectors.toList());
              for (Field childField : childFields) {
                  result.children.add(getClassFieldData(childField, fieldTypeActualClassArguments));
              }
          }
      
          return result;
      }
      
      private String getGenericTypeName(ParameterizedType parameterizedType, 
                                        Map<TypeVariable<?>, Type> actualClassArguments) throws Exception  {
          List<String> genericParamJavaTypes = new ArrayList<>();
          for(Type typeArgument : parameterizedType.getActualTypeArguments()) {
              if (typeArgument instanceof TypeVariable<?>) {
                  TypeVariable<?> typeVariable = (TypeVariable<?>) typeArgument;
                  if(actualClassArguments.containsKey(typeVariable)) {
                      typeArgument = actualClassArguments.get(typeVariable);
                  } else
                      throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found",
                              typeArgument.getTypeName(), parameterizedType.getTypeName()));
              }
      
              if(typeArgument instanceof ParameterizedType) {
                  ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument;
                  Map<TypeVariable<?>, Type> typeActualClassArguments = mapTypeActualClassArguments(
                          (Class<?>)parameterizedTypeArgument.getRawType(),
                          typeArgument, actualClassArguments);
                  genericParamJavaTypes.add(getGenericTypeName((ParameterizedType) typeArgument, typeActualClassArguments));
              }
              else if (typeArgument instanceof Class<?>)
                  genericParamJavaTypes.add(((Class<?>) typeArgument).getCanonicalName());
              else
                  throw new Exception(String.format("For generic parameter %s of type %s, the corresponding actual type of generic parameter was not found", typeArgument.getTypeName()));
          }
      
          Class<?> rawType = (Class<?>) parameterizedType.getRawType();
          return rawType.getCanonicalName() + "<" + String.join(", ", genericParamJavaTypes) + ">";
      }
      

      用法:

      public List<TypeFieldTreeNode> getReturnTypeFields(Method method) throws Exception {
          return getTypeFields(method.getReturnType(),
                  method.getGenericReturnType(), Collections.emptyMap());
      }
      

      对于以下测试类型,该解决方案按预期工作:

      • MyClass2&lt;MyClass&lt;Integer&gt;, MyClass&lt;Boolean&gt;, Double&gt;
      • MyClass3&lt;MyClass&lt;Integer&gt;, MyClass&lt;Double&gt;&gt;

      地点:

      public class MyClass<T> {
          public T value;
          public List<String> list;
      }
      
      public class MyClass2<T, V, E> {
          public T value;
          public List<String> strList;
          public List<V> genericList;
          public int[] intArray;
          public E[] genericArray;
          public MyClass<E> genericClass;
      }
      
      public class MyClass3<T, V> extends MyClass2<T, V, Boolean> {
          public T value3;
          public List<V> genericList3;
      }
      

      【讨论】:

        【解决方案8】:
        public static Type[] getGenericTypes(Field field) {
            ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            return actualTypeArguments;
        }
        
        class User{ 
            ...
            private Set<Authority> authorities = new HashSet<>();
            ...
        }
        
        /// usage
        Class c = User.class;
        Field field = c.getDeclaredField("authorities");
        Type[] types = getGenericTypes(field);
        log.info("Types: {}", types); 
        /// result
        Types: class com.fajar.medicalinventory.entity.Authority
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-24
          • 1970-01-01
          相关资源
          最近更新 更多