Java Reflection提供了一种在运行时对Object进行内省的机制。没有第二个想法,这是一个很棒的功能,但它打破了所有重构惯例!
即使在现代IDE中,也没有简单的方法(除了File Search
之外)知道引用了哪个属性以及在哪里。这使得Refactorings变得更加复杂(令人厌烦!)并且容易出错。
坦率地说,不只是Reflection API
; Hibernate mapping files (hbm.xml)
和JSP files
都将属性称为String,当您重构属性名称时,您必须手动更改所有这些位置。
更糟糕的是,Hibernate映射文件或JSP文件的更改会导致运行时错误。
我很想知道其他程序员如何在Java中处理这个问题。有一些工具吗?我使用Eclipse / IBM RAD作为主要开发平台。通常我们使用constant
来定义属性并尽可能使用它,但并不总是可行。
我也很感兴趣其他语言如何处理这个问题!
答案 0 :(得分:7)
Java反射导致许多与动态类型语言(如Python和Ruby)相同的问题。事实上,考虑动态类型语言的一种方法是使用反射调用所有内容,而语言只是为反射提供了一个漂亮,干净的语法。
是的,对于动态类型语言(或反射的大量使用),重构很难。您没有获得良好的Eclipse重构功能。相反,grep成为你的朋友。
根据我的经验,你能做的最好的事情就是建立一个良好的单位测试安全网。这样,如果你在重构期间破坏了一些动态代码,至少在运行测试时你会很快发现它。
如果您正在执行大量静态类型代码,那么如果您没有良好的单元测试基础,则会遇到大麻烦。如果你正在做很多动态类型的代码(包括带有大量反射的代码),没有良好的单元测试基础,你就没有希望成功。
答案 1 :(得分:2)
现代IDE具有以下功能:在重命名类时,他们将在例如xml文件中搜索完全限定名称,以尝试重命名您可能具有的任何引用。不要认为它解决了问题 - 通常你不会绝对引用类名。
此外,这就是为什么在您自己的代码中使用它之前必须特别注意和考虑的原因。
但反思的这个问题是为什么使用注释变得越来越流行。使用注释时问题会减少。
但是让我说,正如上一篇文章正确指出的那样,如果你没有良好的单元测试安全网,任何一种重构,无论你是否使用大量反射,都是危险的。
答案 2 :(得分:2)
我们实际上已经开发了一个Eclipse插件,可以在很大程度上解决这个问题。它被称为RefaFlex: http://www.feu.de/ps/prjs/rf/
答案 3 :(得分:1)
可以通过在语言中引入更多“文字”来改进重构。例如。 imho .class literal是确保某些模型的编译时安全性的好方法。但是,重要的是,有时候,我想失去编译时的安全性。字符串是表达两层之间松散耦合契约的最简单但最强大的方法,因为你可以根据正则表达式操作或匹配它们等等。
反思的真正问题是API的冗长使用。这是灵活性的主要成本。
<强> PS 强>
项目硬币可以在未来某处引入一些新的语言构建来增强这一领域。
答案 4 :(得分:0)
您可能对使用IntelliJ IDEA感兴趣,它还会在注释和字符串常量中搜索重构的类名。
答案 5 :(得分:0)
嗯,这是IDE制作出售昂贵的高级版本的另一个机会,这些版本将识别和重构特定配置文件中使用的类名。
或者,这种重复出现的情况可以由对这些文件执行健全性检查的测试套件处理,即检查所有被引用的类和方法是否存在。这些特定于一种文件格式,但通常相对容易编写,然后可用于检查该格式的所有文件。但是对于直接的,“手动”使用反射API没有通用的解决方案 - 这就是为什么它通常不鼓励。
答案 6 :(得分:0)
另外,如果您想通过混淆保护代码,Reflection也会引发问题。典型的混淆工具现在要求您维护所有不需要混淆的文件的列表,以便所有XML配置文件的反射都能正常工作。
也就是说,Eclipse IDE的J2EE版本以及Hibernate,Spring等主要框架的合适插件将在处理重构方面做得相当不错。单元测试将缩短测试周期,但关注的是有时单元测试还依赖于某些XML配置,迫使您使用反射。因此,可以在重构时将单元测试与代码分开。
答案 7 :(得分:0)
你知道的taggin类,方法,字段可以通过反射访问吗?当您更改名称时,IDE可能会发出警告。
答案 8 :(得分:0)
当您在编译时知道您要查找的内容时,可以避免使用dp4j.com编写反射API。
关于xml映射,它们很痛苦,我也熟悉NetBeans平台,而JPA2则不太熟悉。好消息是注释正在接管,这再次提供了编译时检查。 我不确定Hibernate,但JPA和NetBeans(more as of 7)都提供了xml映射的注释等价物。
我还开发了SqlWrapper以避免在JDBC中使用字符串。更复杂(和复杂)是JPA2的标准API。