我正在努力将一个大型代码库从一个版本的 API 移植到另一个版本(特别是 Hadoop CDH3 到 Hadoop CDH4)。
在这些库的“升级”过程中,有人决定将一个常用的具体类 (JobContext) 更改为一个接口(interface),并将其所有功能移至一个子类 (JobContextImpl) 中。通常这是一个相当直接的提议。但是,我们仍然需要保持对旧版本库的支持,从而支持类作为具体和接口(interface)。
我们显然可以有 2 套不同的 jar,我们可以根据我们使用的 hadoop 版本交换它们,但这会给我们带来很多不必要的麻烦。我想创建一个可以针对两个 hadoop 版本运行的版本。
自然地,工厂模式会是您首先想到的,但问题是新版本中的实现类在以前的版本中不存在,因此代码将仅针对一组一次库,并且只针对一个库运行。
接下来,我尝试使用 groovyscript 和一些巧妙的反射来检测类路径中库的版本。我能够实例化对象,但使用一个我没有编译的库给了我:
IncompatibleClassChangeError:找到接口(interface) org.pain.MyContext,但类是预期的
编辑: 总之,我需要能够实例化一个可以是具体类或接口(interface)的类。我可以检测到它是哪个,如果它是一个接口(interface),我知道实现在哪里,但如果是具体的,那么该实现类不存在。
最佳答案
没有办法让 JVM 忽略二进制不兼容;即同一类型的相互矛盾的定义。
可能可以解决这个问题,但会非常尴尬。
您需要做的是:
- 消除对
JobContext
的所有直接和间接引用来自您的源代码的类, - 替换所有
JobContext
类型的变量与Object
- 替换对采用
JobContext
的方法和构造函数的所有调用作为参数或通过反射方法或构造函数调用将其作为结果返回,使用Class<?>
对于JobContext
您使用Class.forName(...)
获得的.
简而言之,如果你能摆脱代码使用或依赖静态加载的所有地方 JobContext
, 那么你将不会得到任何 IncompatibleClassChangeError
该类的异常(exception)情况。
老实说,我认为您最好针对两个 Hadoop API 分别编译您的代码库。
关于java - 实例化可以是具体类或接口(interface)类的 Java 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16998367/