【发布时间】:2014-10-31 18:12:49
【问题描述】:
我们有一些遗留的反射代理生成代码,如果你把它看成一个黑盒子,它们基本上是这样工作的:
Object someObject = new Anything();
Object debugObject = ProxyUtils.wrapWithDebugLogging(someObject);
wrapWithDebugLogging 接受任何对象并覆盖它可以的任何方法(如果你正在扩展一个真实的类,最终方法显然是无法修复的),拦截它以记录有关调用的消息,然后调用真实的方法。
在内部,它使用 cglib 来完成工作,并且在构造代理之前有一些保护性逻辑,因为匿名类是最终的,但可以通过使用它们实现的超类或单个接口来处理:
Class<?> clazz = someObject.getClass();
Class<?> interfaces = clazz.getInterfaces();
// Anonymous classes are final so you can't extend them, but we know they only have one
// superclass or one interface.
if (clazz.isAnonymousClass()) {
clazz = interfaces.length > 0 ?
interfaces[0] : primaryType.getSuperclass();
}
Enhancer enhancer = new Enhancer();
if (clazz.isInterface()) {
interfaces.add(clazz);
} else {
enhancer.setSuperclass(primaryType);
}
enhancer.setInterfaces(interfaces.toArray(new Class[interfaces.size()]));
问题在于 Java 8 的“lambda”类为 isAnonymousClass() 返回 false。但我们希望将它们与匿名类完全相同。
pointed out before 一直没有办法确定一个类是“设计”的 lambda 类。但这在我看来更像是反射 API 中缺少的东西,而且这肯定不是 Java 第一次“忘记”向新 API 添加明显的东西。
那么有没有一种明智的方法来区分 lambda 和非 lambda,而无需在 API 中提供此功能?我可以看到 isSynthetic() 返回 true,但它也可能对各种其他事物返回 true。
【问题讨论】:
-
为什么不检查
Class是否为final和Modifier.isFinal(..)? -
如果我们对所有 final 类都使用了这个技巧,你可以找到一个 final 类,该类具有在 final 类本身上定义的 final 方法。在这种情况下,该方法不会由代理实现,因此如果有人调用它,您将收到 NoSuchMethodError。出于这个原因,我们对允许通过哪些最终课程持保守态度。也许这意味着我们应该只检查所有方法都存在于超类或接口之一上的最终类。我不确定这是否是一个好的启发式方法。
-
不,它没有被“遗忘”。它被故意遗漏了,因为它会违反语言的抽象。
-
@BrianGoetz 忽略它违反了反射 API。所以你赢了一些,你也输了一些。
-
这没有意义。你不能继承 any
final类,所以问final类是否有final方法是没有意义的。您不能覆盖其中任何一个。另一方面,当继承超类或实现final类的接口时,您可以重新声明方法,而不管当时不相关的final类是否将它们声明为final。如果您坚持自己的逻辑,则很容易构建既不是匿名也不是 lambda 芽的示例仍然会破坏您的代码。
标签: java reflection lambda java-8 cglib