Reflection 避免错误所需的反射?

Reflection 避免错误所需的反射?,reflection,java,Reflection,Java,我正在对一个库编程 在版本1中,该库有一个方法getFoo(),该方法返回一个映射 在版本2中,该方法getFoo()现在返回一个集合 我认为我的代码可以很高兴地: Object foo = library.getFoo(); 并在库返回地图或集合时工作 然而,当我针对库的版本1编译代码,但针对版本2运行代码时,我得到java.lang.NoSuchMethodError:getFoo()Ljava/util/Map 至少这是发生在你身上的事情 java version "1.7.0_21

我正在对一个库编程

在版本1中,该库有一个方法getFoo(),该方法返回一个映射

在版本2中,该方法getFoo()现在返回一个集合

我认为我的代码可以很高兴地:

  Object foo = library.getFoo();
并在库返回地图或集合时工作

然而,当我针对库的版本1编译代码,但针对版本2运行代码时,我得到java.lang.NoSuchMethodError:getFoo()Ljava/util/Map

至少这是发生在你身上的事情

java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.04.1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
我现在已经通过使用反射解决了这个问题,但我认为没有必要这样做


所以我的问题是,做Object foo=library.getFoo()安全吗?如果答案是“有时”或“视情况而定”,那么为什么在这种情况下不安全

当您使用版本1编译代码时,您的类字节代码具有此方法的条目,返回类型为Map。在运行时,类被加载,类定义有getFoo(),返回类型为Map,因此JVM无法找到该方法,因为您是针对具有不同返回类型的方法(在您的情况下设置)的不同版本的类运行该方法。

您得到的错误完全有效

选项1:在代码中使用反射来动态地对运行时找到的库的任何版本执行正确的操作

选项2:如果希望代码与库的任一版本一起运行,则需要在编译时两个版本都可用。您将需要一些代码来决定在运行时使用哪个版本,并有条件地执行为调用库的正确版本而编译的代码。如果库作者不友善,您可能最终不得不解决类名冲突

反射(选项1)可能是最简单、最灵活的方法


您可能希望创建一个包装器API,以抽象出库的两个版本之间的差异,这样就不会泄漏到应用程序的其余部分。

使用不同的库编写代码,并使用不同的库运行相同的代码本身就是一个问题。我认为您应该尝试纠正库不匹配,而不是在代码中处理它。这是一个非常棘手的问题。。。你会认为这会很好。现在我知道
Map
Set
都是接口,但它们并不是很多。检查javadocs中的并显示
Set
扩展了
Collection
,而
Map
没有扩展任何内容。这与此有关吗?也可能是
Map
的修饰符,而
Set
只有
。事实上,我认为第二个想法就是问题所在。由于它返回一个
集合
,但一个映射给出两个
,因此它们不兼容。也许他们只是给出了默认的错误信息,而没有为这个案例创建新的错误信息。看起来你的问题与你的情况并不完全相关。使用对象作为基类的问题可以通过查看两个对象的继承树来解决。您的问题不是关于对象,而是关于Java在运行时无法找到getFoo()Ljava/util/Map。这与最终存储结果的变量无关。