【问题标题】:Do Eclipse's Refactoring Tools Violate The Java Language Specification?Eclipse 的重构工具是否违反了 Java 语言规范?
【发布时间】:2010-06-17 07:33:46
【问题描述】:

在 Eclipse 3.5 中,假设我有这样的包结构:

 tom.package1
 tom.package1.packageA
 tom.package1.packageB

如果我右键单击 tom.package1 包并转到 Refactor->Rename,“重命名子包”选项将显示为复选框。如果我选择它,然后将tom.package1 重命名为tom.red,我的包结构最终会是这样的:

tom.red
tom.red.packageA
tom.red.packageB

但我听说Java's packages are not hierarchical。 Java 教程back that up(参见关于包的表观层次结构的部分)。在这种情况下,Eclipse 似乎将包视为分层的。

我很好奇为什么访问说明符不能允许/限制访问 previous question 中的“子包”,因为我知道我以前在某处看到过“子包”。

那么 Eclipse 的重构工具是不是故意误导了易受影响的年轻人,从而助长了“子包”的神话?还是我在这里误解了什么?

【问题讨论】:

  • 顺便说一句,默认情况下不检查“重命名子包”这一事实是一个很好的论据,他们没有试图误导任何人
  • 我没有注意到你注意到的行为,但这可能只是一个版本问题(我使用的是 3.6),如果不是的话:右键单击包资源管理器中的包并使用 Refactor 子菜单的 Rename 那里,它似乎具有您需要的效果(无论如何对我来说?)。
  • 不,这不是版本问题,两个菜单项肯定会绑定到相同的代码,但是...实际上我认为您可能是对的。我刚刚尝试在包上删除,Eclipse 询问我是否还想删除“子包”(虽然这并不违反 JLS),如果选择了,那么它将删除,因为您注意到重命名(而不是重命名?)... . 奇怪???

标签: java eclipse


【解决方案1】:

在这种情况下,Eclipse 不可能违反 JLS,因为它与编译或运行 Java 源代码或字节码无关。

重构工具的行为与它们一样,因为这种行为对开发人员很有用。该行为对开发人员很有用,因为出于许多意图和目的,我们确实将包视为层次结构(a.b.c 与 a.b 有某种关系,即使该关系在项目之间不一致)。这并不意味着 Java 本质上将它们视为层次结构。

人们将包视为非常分层的一个示例是配置日志框架,例如 log4j。同样,它不是 log4j 固有的,但这是人们在实践中使用它的方式

【讨论】:

  • 这很有趣,我曾认为 Eclipses JDT 的核心部分之一是增量编译器。我想知道,他们是如何在不接触语言规范的情况下实现这一目标的?我明白你所说的重构工具只是为了方便(我确实发现它们是),但是当语言规范明确表示它可能不是时,Eclipse 似乎总是希望将 a.b.c 视为与 a.b 相关.我的问题可能措辞有点耸人听闻。也许应该是“重构工具是否在假装语言中不存在的关系?
  • @Tom:首先,我说 Eclipse 在这种情况下不可能违反 JLS。重构工具与项目的编译或运行时行为无关。这就像创建一个 bash 脚本来做同样的事情并说这违反了 JLS。其次,我不明白你怎么能说 Eclipse 似乎总是将它们视为相关的当默认包重命名不重命名子包时。这整个问题是因为他们使用“子包”这个词吗?
【解决方案2】:

Java 包不是分层的,因为从包 A 导入所有内容不会从包 A.B 导入所有内容。

然而,Java 包确实直接对应于文件系统上的目录结构,并且目录是分层的。所以 Eclipse 正在做正确的事情 - 它正在重命名目录,这会自动更改重命名目录的子目录的父目录的名称(非常明显)。

【讨论】:

  • 请注意,默认情况下它实际上并没有这样做。当您偏离默认值并选中该选项以重命名子包时,会发生重命名目录。但无论哪种方式都是正确的。
  • @Mark Peters:如果您不采用该选项会怎样 - 创建一个新目录并移动所有文件,但同时保留旧目录以包含子目录?
  • 是的,这正是它的作用。如果在 Package Explorer 中使用“Flat” Package Presentation,这就是您所期望的。如果使用“层级”演示,可能会让您大吃一惊。
  • 它在文件系统上做正确或预期的事情,我明白了。但是除了我之外没有其他人发现它指的是“子包”令人困惑。没有Java子包这样的野兽,对吧?
  • @Tom Tresansky:当然有。来自 JLS (java.sun.com/docs/books/jls/second_edition/html/…):“包的命名结构是分层的(第 7.1 节)。包的成员是类和接口类型(第 7.6 节),它们在包的编译单元中声明,并且 subpackages,其中可能包含自己的编译单元和子包。”它只是指另一个包中的一个包。
【解决方案3】:

甚至java本身也有分包的概念:

http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/java.html

java -ea[:"..." | :]

启用断言。默认情况下禁用断言。

如果没有参数,则 enableassertions 或 -ea 启用断言。一个以“...”结尾的参数,该开关启用指定包和任何子包中的断言。如果参数只是“...”,则开关启用当前工作目录中未命名包中的断言。如果一个参数不以“...”结尾,则该开关启用指定类中的断言。

如果单个命令行包含这些开关的多个实例,它们会在加载任何类之前按顺序处理。因此,例如,要运行仅在包 com.wombat.fruitbat(以及任何子包)中启用断言的程序,可以使用以下命令:

java -ea:com.wombat.fruitbat... <Main Class>

【讨论】:

  • 所以包是非分层的,但是通过添加明确暗示分层的前缀来正式引用它们。太棒了!
  • @Tom Tresansky:你仍然没有抓住重点。层次结构在目录结构中,java包直接对应。当我们说 Java 包是非分层的时,我们指的是一个非常具体的事情:导入包中的所有内容并不会从其子包中导入任何内容。如果您更愿意通过不使用“非分层”一词来消除两者的歧义,那很好。
  • @Tom:您似乎认为教程是绝对可靠的(它们不是;实际上它们经常是错误的),而且在不同上下文中使用的相同术语指的是同一件事。 JLS ch 的第二段。 7 处理包裹说The naming structure for packages is hierarchical。它们在该上下文中是分层的。在导入的上下文中,它们不是分层的 *因为import java.awt.* 不导入java.awt.image.*。上下文,上下文,上下文!
【解决方案4】:

Java 的包不是分层的,但 Eclipse 将包存储在系统的文件结构中。

tom.package1.packageA 在 Windows 文件系统上表示为 tom/package1/packageA

当您要求 Eclipse 重构包名时,您是在要求 Eclipse 更改文件系统目录结构的名称。

您可以在 Eclipse 中使用以下软件包:

tom.package1.packageA
tom.package2.packageB
tom.package3.packageC

您将拥有不同的二级文件系统目录。

【讨论】:

  • javac also 希望您的源文件具有这样的文件层次结构。