使用 Java 反射来查找集合的元素类型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10945993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:11:41  来源:igfitidea点击:

Using Java Reflections to find Collection's element type?

java

提问by theV0ID

Consider the following Java code:

考虑以下 Java 代码:

public class Test
{
    private Foo< String, String > foo1;
    private Foo< Integer, Integer > foo2;
}

public class Foo< T, V >
{
    private Bar< V > bar;
    private T a;
}

public class Bar< T >
{
    @MyAnnotation
    private List< T > list;
}

First, starting with the class named 'Test', I'm searching all fields recursively, which are annotated with 'MyAnnotation' and whose type is derived from 'java.lang.Collection'. For the given example, the results would be:

首先,从名为“Test”的类开始,我递归地搜索所有字段,这些字段使用“MyAnnotation”进行注释并且其类型派生自“java.lang.Collection”。对于给定的示例,结果将是:

  • Test.foo1.bar.list
  • Test.foo2.bar.list
  • 测试.foo1.bar.list
  • 测试.foo2.bar.list

It's obviosly clear, that the first one can only take strings for its elements, whereas the second one can only take integers.

很明显,第一个只能为其元素取字符串,而第二个只能取整数。

My Question is: What is the best (easiest) way to find all Collection fields annotated with 'MyAnnotation' and tell their element type?

我的问题是:找到所有用“MyAnnotation”注释的集合字段并告诉它们的元素类型的最佳(最简单)方法是什么?

Finding annotated fields from type java.lang.Collection is not the problem. But how can we get a result which looks like the following one for the given example?

从类型 java.lang.Collection 中查找带注释的字段不是问题。但是,对于给定的示例,我们如何才能获得如下所示的结果?

  • Test.foo1.bar.list< String >
  • Test.foo2.bar.list< Integer >
  • Test.foo1.bar.list<String>
  • Test.foo2.bar.list<整数>

I've tried several approaches, which always gave me 'Object' as the collection's element type instead of 'String'.

我尝试了几种方法,这些方法总是给我“对象”作为集合的元素类型而不是“字符串”。

I'm really stuck on this. Many thanks in advance!

我真的坚持这一点。提前谢谢了!

采纳答案by Mattias Buelens

This is not possible due to Java's type erasure. When compiled, the generic types will be replaced by raw types, resulting in something like this:

由于 Java 的类型擦除,这是不可能的。编译时,泛型类型将被原始类型替换,结果如下:

public class Test
{
    private Foo foo1;
    private Foo foo2;
}

public class Foo
{
    private Bar bar;
    private Object a;
}

public class Bar
{
    @MyAnnotation
    private List list;
}

The actual types are then filled in places where you are directly working with foo1and foo2. For example, the following code:

然后在您直接使用foo1和 的地方填充实际类型foo2。例如,以下代码:

Test test = new Test();
List<String> a = test.foo1.bar;
String b = a.get(0);
Integer b = test.foo2.a;

will be translated to something like:

将被翻译成类似的东西:

Test test = new Test();
// The generic type is erased here...
List a = test.foo1.bar;
// ...and a cast is added here
String b = (String) a.get(0);
Integer b = (Integer) test.foo2.a;

Long story short: there's no way you can retrieve that type, since it is discarded at compile time.

长话短说:您无法检索该类型,因为它在编译时被丢弃。

回答by UVM

May be you can try like this:

也许你可以这样尝试:

Field field = Test1.class.getField("list");

Type genericFieldType = field.getGenericType();

if(genericFieldType instanceof ParameterizedType){
    ParameterizedType aType = (ParameterizedType) genericFieldType;
    Type[] fieldArgTypes = aType.getActualTypeArguments();
    for(Type fieldArgType : fieldArgTypes){
        Class fieldArgClass = (Class) fieldArgType;
        System.out.println("fieldArgClass = " + fieldArgClass);
    }
}

This will return fieldArgClass = java.lang.String

这将返回 fieldArgClass = java.lang.String