问题描述
我想通过 Java 反射获取对类中定义的 java.util.Vector
私有变量的引用并对其进行迭代。类中变量的声明如下:private final Vector<Class<?>> classes = new Vector<>();
实际上,我试图阅读 Vector 的课程是这样的:java.lang.ClassLoader
我需要的对象来自于此(我需要使用 getSuperclass()
两次,因为在应用程序服务器中 ClassLoader.getSystemClassLoader() 返回一个特定于 weblogic 的类加载器类,而我需要的字段来自父类):
ClassLoader.getSystemClassLoader().getClass().getSuperclass().getSuperclass()
以及调试模式下的字段,我需要:
关于上下文的一点:java 反射代码将在一个简单的 servlet 中运行,部署到应用服务器。
我可以使用以下代码获取 java.lang.reflect.Field
:
Class c = ClassLoader.getSystemClassLoader().getClass().getSuperclass().getSuperclass();
Field classesField = c.getDeclaredField("classes");
classesField.setAccessible(true);
Type type = classesField.getGenericType();
System.out.println(type.getTypeName()); //java.util.Vector
但我无法获得从 java.lang.reflect.Field
到 java.util.Vector
的引用,以便我可以从中读取项目。
我试过这样的方法:
// 1:
Vector v = new Vector<>();
// ERROR: Can not set final java.util.Vector field java.lang.classLoader.classes to java.util.Vector
// 2:
public static class VectorWrapper {
private Vector<Class<?>> v = new Vector<>();
}
VectorWrapper v = new VectorWrapper();
// ERROR: Can not set final java.util.Vector field java.lang.classLoader.classes to a.b.c.Test$VectorWrapper
// try to get the vector
Object o = classesField.get(v);
Vector classes = (Vector<Class<?>>) o;
System.out.println(classes.size());
上面的代码不起作用,抛出异常。
似乎是因为类中的字段定义为final
,所以我无法获取引用。也许我需要获得 Vector
的迭代器而不是 Vector
本身?但我不确定。
如何在此 Vector 字段上循环并从中获取项目?
-- 更新 --
我创建了一个简单的测试应用程序,没有应用程序服务器,只使用纯Java。我尝试过 Java 11,但那台机器上只有这个 Java 版本。但我想这与 Java 8 的行为相同。只需复制并粘贴代码,然后执行它即可查看异常:
Can not set final java.util.Vector field java.lang.classLoader.classes to java.util.Vector
代码:
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Vector;
public class ReflectionTest {
public static void main(String[] args) throws Exception {
Class c = ClassLoader.getSystemClassLoader().getClass().getSuperclass().getSuperclass().getSuperclass();
printFields(c);
printValue(c,"classes");
}
private static void printFields(Class c) {
System.out.println(c.getTypeName());
int i = 0;
Field[] fields = c.getDeclaredFields();
for (Field m : fields) {
i++;
System.out.println(i + ". " + m.getType().getName() + ":" + m.getName());
}
System.out.println("-------------------------------------");
}
private static void printValue(Class c,String fieldName) throws Exception {
Field classesField = c.getDeclaredField(fieldName);
classesField.setAccessible(true);
Type type = classesField.getGenericType();
System.out.println(type.getTypeName());
Vector v = new Vector<>();
Object o = classesField.get(v);
Vector classes = (Vector<Class<?>>) o;
System.out.println(classes.size());
}
}
解决方法
您需要保留对 ClassLoader 对象的引用,以便您可以调用 classesField.get(classLoader)
。以下是一些可能有用的示例代码:
@Test
public void testVector() throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Class classLoaderClass = null;
for (Class c = classLoader.getClass(); c != Object.class; c = c.getSuperclass()) {
System.out.println(c.getName());
if (c == java.lang.ClassLoader.class) {
classLoaderClass = c;
}
}
System.out.println("found a " + classLoaderClass.getName());
Field classesField = classLoaderClass.getDeclaredField("classes");
classesField.setAccessible(true);
Type type = classesField.getGenericType();
System.out.println(type.getTypeName()); //java.util.Vector
Object o = classesField.get(classLoader);
System.out.println("o is a " + o.getClass().getName());
if (o instanceof Vector) {
Vector v = (Vector) o;
v.forEach(e -> {
System.out.println(e);
});
}
}
更短的版本:
@Test
public void testVector2() throws Exception {
Field classesField = java.lang.ClassLoader.class.getDeclaredField("classes");
classesField.setAccessible(true);
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
Vector<Class<?>> v = (Vector<Class<?>>) classesField.get(classLoader);
System.out.println("ClassLoader has " + v.size() + " classes");
}