【发布时间】:2017-01-15 06:34:47
【问题描述】:
我已经完成了我的研究,但我仍然无法调用它是否可能。这个问题听起来像是一个特例。然而,我试图尽可能地概括它。
在 Java 中,我知道可以使用反射来公开对象的字段(比如x)。而且我知道可以更深入地公开子对象的字段,例如x 的字段。但是,当涉及到通用对象时,这变得很棘手。
为了更好地解释这一点,假设我们有以下两个简单的类:
package reflection;
import java.util.*;
public class Subject {
public List<SomeUserDefinedObj> myListOfObj =
new ArrayList<SomeUserDefinedObj>();
public SomeUserDefinedObj singleObj = new SomeUserDefinedObj();
public Subject(){
myListOfObj.add(new SomeUserDefinedObj());
}
}
和
package reflection;
public class SomeUserDefinedObj {
public int x;
}
我们有以下测试类,它将通过反射检查Subject
package reflection;
import java.lang.reflect.*;
public class Test {
public static void main(String[] args) {
Subject subject = new Subject();
Class<?> c = subject.getClass();
for (Field field:c.getDeclaredFields()){
System.out.println("Field in " + c.getName() + ": " + field.getName());
Class<?> nestedClass = field.getType();
for (Field nestedField:nestedClass.getDeclaredFields()){
System.out.println("\tField in " + nestedClass.getName() + ": " + nestedField.getName());
}
}
}
}
这个测试的输出是:
Field in reflection.Subject: myListOfObj
Field in reflection.Subject: singleObj
Field in reflection.SomeUserDefinedObj: x
现在,我们可以看到检索到单个对象的内容,但列表好像是空的。我知道有一些方法可以使用对象本身的实例来获取列表的类型(您可以从中迭代列表中的对象),例如subject 来自 Test 喜欢 here。例如,我可以做Object myInstance = field.get(subject); 并且从他们我将能够确定列表中元素的类型并迭代它们(经过测试和工作)。
但是,(在这里我的问题可能是具体的)我无权访问该实例(由于使用遗留代码而设计阻止了这种奢侈)。所以,我试图通过只使用反射类对象来实现这个目标,例如c 来自 Test。我找到了一些资源,可以帮助我确定列表中元素的类型,例如here 和here(我测试了它们并且它们有效)。然而,这个(第一)并没有授予实际类型,因为该类型可能是一个抽象类,(第二)我看不到任何从那里获取列表元素信息的方法,无论类型是否是抽象的。据我了解,检索给定此方法的类型只能保证它将返回给您使用列表初始化的类型,而不是元素(甚至类型可能不准确,如解释的那样)。
最后,鉴于我所说的所有情况(仅使用反射对象而不是实际实例对象)。 那么,问题就变成了,是否可以在不使用反射访问实际实例的情况下检索 Collection 元素?
【问题讨论】:
-
一般情况下不会。编译时泛型存储在源代码和accessible through reflection 中,但泛型本身是erased at compile time,因此您无法访问运行时泛型类型。这意味着您可以在示例中访问
Collection的类型,因为它是“硬编码”的 - 如果class Subject在Collection的类型中是通用的,这是不可能的。 -
扩展 Collection 的泛型类和用户定义的泛型类型类有什么区别。我问这个是因为,在我的一个测试中,我尝试创建自己的泛型类型类(它拥有并返回一个类型并没有什么花哨的)。并且使用上面示例中的反射,我能够检索它的元素!
-
重点是,如果您有somewhere 编写了实际的泛型类型,那么您可以通过类型参数跟踪它以计算出运行时泛型类型。这在现实中可能极其复杂,并且通常不可能,因为某些泛型类型是在运行时确定的——例如反序列化的东西。一个很好的例子参见 Spring 的
GenericTypeResolver- 开源和测试代码是一个很好的信息来源。
标签: java generics reflection collections