我在第三方JAR中有一个设计很差的类,我需要访问它的一个私有字段。例如, 为什么我需要选择私人领域是必要的?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
如何使用反射来获取stuffIWant的值?
我在第三方JAR中有一个设计很差的类,我需要访问它的一个私有字段。例如, 为什么我需要选择私人领域是必要的?
class IWasDesignedPoorly {
private Hashtable stuffIWant;
}
IWasDesignedPoorly obj = ...;
如何使用反射来获取stuffIWant的值?
当前回答
Java 9引入了变量句柄。您可以使用它们访问类的私有字段。
示例代码如下所示:
var lookup = MethodHandles.lookup();
var handle = MethodHandles
.privateLookupIn(IWasDesignedPoorly.class, lookup)
.findVarHandle(IWasDesignedPoorly.class, "stuffIWant", Hashtable.class);
var value = handle.get(obj);
使用Lookup和VarHandle对象作为静态final字段也是可取的。
其他回答
试试Apache common -lang3中的FieldUtils:
FieldUtils.readField(object, fieldName, true);
附注:在我看来,反思是邪恶的。
使用Soot Java Optimization框架直接修改字节码。 http://www.sable.mcgill.ca/soot/
Soot完全是用Java编写的,并且适用于新的Java版本。
使用XrayInterface工具非常简单。只需定义缺失的getter /setter,例如:
interface BetterDesigned {
Hashtable getStuffIWant(); //is mapped by convention to stuffIWant
}
用x射线照射你设计糟糕的项目:
IWasDesignedPoorly obj = new IWasDesignedPoorly();
BetterDesigned better = ...;
System.out.println(better.getStuffIWant());
在内部,这依赖于反思。
您需要完成以下操作:
private static Field getField(Class<?> cls, String fieldName) {
for (Class<?> c = cls; c != null; c = c.getSuperclass()) {
try {
final Field field = c.getDeclaredField(fieldName);
field.setAccessible(true);
return field;
} catch (final NoSuchFieldException e) {
// Try parent
} catch (Exception e) {
throw new IllegalArgumentException(
"Cannot access field " + cls.getName() + "." + fieldName, e);
}
}
throw new IllegalArgumentException(
"Cannot find field " + cls.getName() + "." + fieldName);
}
还有一个没有提到的选项:使用Groovy。Groovy允许您访问私有实例变量,这是该语言设计的一个副作用。无论是否有字段的getter,都可以使用
def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()