Java包结构中反向域名的意义是什么?

50
为什么在Java包中要使用反向域名结构,比如com.something或org.something? 我知道这样做可以带来某种独特性,但为什么需要这种独特性?

3
这实际上更符合从一般到具体的从左到右传递的惯例——可以想象文件路径或杜威十进分类法。相反地,你可能会问为什么域名违反这个惯例(或者为什么我们以难以排序的方式书写日期)。 - harpo
@harpo:没错。域名和日期最好倒过来写。 - Leo Jweda
“server.domain.tld”语法是一种非常英语化的表达方式(在对象之前使用修饰词——“红球”)。例如,西班牙语采用更为逻辑化的“对象修饰词”语法(“bola roja”)。 - dlchambers
6个回答

59

关于为什么我们要反向进行操作:想象一下你有两个重要的软件包,一个是会计软件包,另一个是图形软件包。如果你按照“正常”的顺序指定它们:

accounting.mycompany.org
graphics.mycompany.org

这意味着存在一个重要的会计软件包,其中的一个子部分是针对mycompany的,而该软件包的一个子部分称为org包,您实际上正在使用它。但是,你想要这个:

org.mycompany.accounting
org.mycompany.graphics

这更有意义。在所有来自组织(org)的包中,你特别关注mycompany,它有两个子包,分别是accountinggraphics


10
请注意,遗憾的是 Java 不支持子包,子包与其父包(在可见性方面)并没有更近的关系,就像完全不相关的包一样。当然,它仍然对代码组织非常有用。 - Thilo
2
这仅仅意味着 org 是具体的包,因为你并没有完全举出例子。如果第一部分是具体的包会怎样呢?那是否不可能呢?在从右到左阅读的国家,这个反驳是站不住脚的 :P - sinni800
1
@sinni800:我对你的评论打-1。当你用Java编写代码时,它是从左到右书写的。此外,当你有a.b.c.d时,它意味着你从类a开始,嵌套到其字段b,再嵌套到该字段的c,然后嵌套到该字段的d。类似地,包组织应该也是这样工作的。此外,在Python中,子包装实际上是按照我在这里写出的方式完成的。因此,这不是不可能,但这将是愚蠢的。 - Claudiu
@Claudiu 但是,语言的某些部分(继承自C风格语法)存在从左到右的阅读方式,但在单词层面上存在从右到左的风格。例如函数定义。返回类型首先出现,即使作为人类,您不会将其放在第一位。我只是想说,没有一个普遍的真理,即子包必须从左到右进行排列。不过,我之前并不知道Python的事情。 - sinni800
@sinni800:嗯,是的,一切都是约定俗成。从左到右表示从普遍到更具体的方式非常普遍...你能列举出任何有包但不是从左到右的编程语言吗? - Claudiu
显示剩余6条评论

39

全局唯一的包名可以避免来自不同来源的库之间的命名冲突。而不是创建一个新的全局名称数据库,而是使用域名注册表。根据JLS:

生成唯一包名的建议约定仅是一种在现有广为人知的唯一名称注册表上搭载包命名约定的方式,而不是必须创建一个专门的注册表来存储包名。


5
DNS 实际上与此毫无关系(不过还是给你点赞) - Fredrik
6
@Fredrik实际上没有执行DNS查找,但JLS中提到的“广为人知的唯一名称注册表”是指“域名系统”。 - Laurence Gonsalves

4
正如你所说,将反向域名作为基本包名可以确保其唯一性。假设两个公司的域名分别为example.com和example.org,他们都在自己的框架中定义了Employee类。现在如果你同时使用这两个框架,你将无法确定你想要在代码中使用哪个Employee类,但如果它们分别定义在com.example和org.example包中,你就可以明确地告诉编译器/JVM你正在引用哪个类。如果没有定义唯一的包,你将得到编译错误或运行时错误,例如,如果你使用com employee类,但是org employee类先从classpath中加载,你将会得到一个运行时错误,因为这两个employee类可能没有相同的结构。

3
唯一性对于类加载非常重要。
它有助于避免命名冲突。如果有相同包名和类名的类,则在尝试加载这些类时会发生冲突。
如果存在多个包含相同名称类的库(jar),则通常会发生这种情况。
另请参见此链接

你在谈论什么类型的加载?给它独特的命名如何防止可能的冲突?我认为,如果类名也相同,则在加载期间发生的任何冲突都会发生。 - Vaishak Suresh
@Vaishak:这个假设是错误的。唯一标识类的名称是包名+类名。如果您在同一个包中,或者已经明确导入了一个包或完全限定的类名,那么您只需使用名称即可。就像拨打电话一样,如果您已经在同一个区域内,通常不需要指定区号,但您提供的完整电话号码仍将包括区号。 - Fredrik
@Fredrik 我的假设与您的解释一致 :) 这就是为什么我说如果类名相同就会发生冲突。但我的问题现在已经得到了回答。谢谢! - Vaishak Suresh

0
如果您需要将代码与第三方软件集成,或者提供给其他人进行集成,则需要确保其独特性。如果不遵循规则,就会增加类命名冲突的风险,并且您将需要重命名大量类来解决此问题。更糟糕的是,您的客户可能需要进行代码重命名。
这也适用于在组织中生成不同项目的代码。

0
正如你所说,它带来了独特性,这在与第三方代码一起工作时尤为需要。例如,假设你正在使用我制作的库。我使用了包“foo”,并在其中有一个名为Bar的类。现在,如果你也使用包名称“foo”,并且你有一个名为Bar的类,这意味着你的实现将覆盖我的Bar实现,使我的实现无法访问。另一方面,如果我的包名称是“com.mydomain.foo”,并且我在那里有我的Bar类,那么你可以自由地在你的一个类中使用名称Bar,两个类仍然可以被唯一地识别和单独使用。
为什么要使用反向域名作为包名?我想这只是一个惯例,以确保每个人都使用独特的命名空间,因为你不应该在你的包名中使用别人的域名。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接