问题
一位 friend 提出了一个有趣的问题。给定以下代码:
public class OuterClass {
private String message = "Hello World";
private class InnerClass {
private String getMessage() {
return message;
}
}
}
在外部类中,如何打印message
变量内容?当然,不允许更改方法或字段的可访问性。
(来源here,不过是个法语博客)
解决方案
解决这个问题的代码如下:
try {
Method m = OuterClass.class.getDeclaredMethod("access$000", OuterClass.class);
OuterClass outerClass = new OuterClass();
System.out.println(m.invoke(outerClass, outerClass));
} catch (Exception e) {
e.printStackTrace();
}
请注意,access$000
方法名称并不是真正标准的(即使这种格式是 strongly recommanded ),一些 JVM 会将此方法命名为 access$0
。因此,更好的解决方案是检查合成方法:
Method method = null;
int i = 0;
while ((method == null) && (i < OuterClass.class.getDeclaredMethods().length)) {
if (OuterClass.class.getDeclaredMethods()[i].isSynthetic()) {
method = OuterClass.class.getDeclaredMethods()[i];
}
i++;
}
if (method != null) {
try {
System.out.println(method.invoke(null, new OuterClass()));
} catch (Exception e) {
e.printStackTrace();
}
}
所以这个问题的有趣点在于突出合成方法的使用。使用这些方法,我可以像在解决方案中那样访问私有(private)字段。当然,我需要用到反射,而且我认为使用这种东西是相当危险的......
问题
作为开发人员,我对合成方法有什么兴趣?什么是使用合成有用的好情况?
最佳答案
正如您所演示的,Java 访问修饰符只是提供信息,可以通过使用反射来规避它们。所以你的问题大致等同于“规避访问修饰符的好处是什么?”除了恶意目的,还想到了调试;例如,您可以从库的外部记录某些库内部的内部状态,而根本不必触及库代码本身。另一个例子是与脚本语言的合作;如果您在编译时不知道哪些类和方法可用,反射可能非常有用。例如,Jython的内部使用了大量的反射。
关于java - 合成方法有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2460502/