2

我一般反对扩展,因为它在类之间创建了非常强的连接,很容易意外中断。

但是,我最终认为我已经找到了一个合理的案例——我想在现有系统中选择使用文件类型的压缩版本。压缩版本几乎与未压缩版本一样快,并且具有完全相同的可用方法(即读取和写入)——唯一的区别在于磁盘上的表示。因此,我让压缩版本扩展了未压缩版本,以便可以使用任何一种文件,只需选择性地实例化另一种类型即可。

public class CompressedSpecialFile extends SpecialFile(){ ... }

if (useCompression){
    SpecialFile = new CompressedSpecialFile();
} else {
    SpecialFile = new SpecialFile();
}

但是,在程序的稍后阶段,我们使用反射:

Object[] values = new Object[]{SpecialFile sf, Integer param1, String param2, ...}
Class myclass = Class.forName(algorithmName);
Class[] classes = // created by calling .getClass on each object in values
constructor = myclass.getConstructor(classes); 
Algorithm = (Algorithm) constructor.newInstance(values)

一切正常,但现在 myclass.getConstructor 类抛出 NoSuchMethodException,因为 SpecialFile 的运行时类型是 CompressedSpecialFile。

但是,我认为扩展应该是这样工作的——因为 CompressedSpecialFile 扩展了 SpecialFile,所以任何接受 SpecialFile 的参数都应该接受 CompressedSpecialFile。这是Java反射的错误,还是我理解的失败?

4

1 回答 1

3

嗯,对这个错误报告的响应似乎表明这是故意的。 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4301875

出于兼容性原因,我们无法进行此更改。此外,我们希望 getConstructor 的行为类似于 getDeclaredMethod,后者也需要完全匹配,因此在不更改另一个的情况下更改一个是没有意义的。但是,可以添加一组额外的方法,这些方法的不同之处仅在于参数类型的匹配方式。在某些情况下,我们可能希望在反射期间在运行时应用编译器静态使用的相同重载解决算法,即在调试器中。但是,使用现有 API 实现此功能并不困难,因此将此功能添加到核心反射的情况很弱。

该错误报告已作为以下错误报告的副本关闭,它提供了更多实现细节: http ://bugs.sun.com/bugdatabase/view_bug.do;jsessionid=1b08c721077da9fffffffff1e9a6465911b4e?bug_id=4287725

解决方法getMethod
的用户必须准确识别传递给参数的类。

评估
这个请求的本质是用户希望 Class.getMethod 应用与编译器相同的重载规则。我认为这是一个合理的要求,因为我看到在某些类型的反射程序(例如调试器和脚本解释器)中经常需要这样做,并且有一个标准的实现会很有帮助,以便每个人都能正确地做到这一点。然而,为了兼容性,现有 Class.getMethod 的行为应该保持不变,并定义一个新方法。有一种情况可以根据足迹忽略此功能,因为它可以使用现有的 API 来实现,尽管效率有些低。另见 4401287。共识似乎是我们应该在反射中提供重载解决方案。
出于兼容性原因, Class.get(Declared)+{Method,Constructor} 实现不应更改;应该引入新的方法。这些方法的规范确实需要修改以定义“匹配”。请参阅错误 4651775。

您可以继续深入研究那些引用的错误和我提供的实际链接(在那里进行了讨论以及可能的解决方法),但我认为这是有道理的(尽管为什么还没有实现一种在反射中反映 java oop 的新方法) , 我不知道)。

就解决方法而言,我认为对于单级深度版本的继承,您可以在每个名称为扩展类的类上调用 getSuperclass() ,但这非常不雅,并且与您仅在您的课程以规定的方式实施。非常笨拙。不过,我会尝试寻找另一种选择。

于 2012-10-01T06:35:23.410 回答