Java中与程序包相对的标识符路径

时间:2018-07-03 21:12:32

标签: java namespaces package project

简介

从C ++移出之后,最大的区别之一就是作用域的不同:在C ++中,每个标识符都是相对于当前范围(classnamespace)的,您可以使用范围解析运算符::开头。

但是,在Java中,我找不到从其他包访问标识符的方法,而不将其导入当前作用域或编写其完整路径。

如果我有几个同名的类,那么这可能是一个问题(然后,在C ++中,我将它们分别命名为Module1 :: Foo和Module2 :: Foo,这在Java中是不可能的,只要我想要请保存我的理智,因为com.company.project.module1.Foo对我的品味来说太长了)。

代码!

下面是一个从Java和C ++访问类Tools.Useless.Foo(没有importusing的示例)

Tools/Useless/Foo.hpp

namespace Tools {
namespace Useless {
class Foo {         
};
}
}

Tools/Bar.hpp

namespace Tools {
...
// Use Foo with a relative identifier
Useless::Foo foo;
// Use Foo with an absolute identifier.
::Tools::Useless::Foo bar;
...
} 

这就是在Java中的外观:

com/company/project/Tools/Useless/Foo.java

package com.company.project.Tools.Useless;

public class Foo { }

com/company/project/Tools/Bar.java

...
// Use Foo with a relative identifier
???
// Use Foo with an absolute identifier.
com.company.project.Tools.Useless.Foo foo;
...

问题

  1. 是否有一种方法可以从软件包Foo访问Tools.Useless,而无需指定Tools.Useless完整的软件包名称(并导入它;因为导入会将其绑定到当前作用域)?
  2. 我做对了吗?我应该如何使用几个同名的类?我应该避免这种情况,还是只使用“ package。*”导入它们以绕过它?

解决方案

  1. 使用更多的包描述类名(例如ToolsUselessFoo而不是Foo)。
  2. 使用import path.to.module.*而不是import path.to.module.Foo导入所有内容,然后访问Foo所需的软件包以解决任何歧义。问题在于,有时包名称具有含义(例如Tools.Useless.FooTools.Useful.Foo)。

1 个答案:

答案 0 :(得分:1)

Java软件包未嵌套。尽管它们的名称可能具有通用前缀,但在Java编程语言中没有任何意义。

当存储是文件系统时,其类文件存储在嵌套目录中的事实也没有其他含义。当类存储在jar文件中时,它们会以与限定名称匹配的条目名称进行存储,而实际上根本不形成目录(尽管许多工具都喜欢将它们呈现为仿照文件系统的分层结构显示)。

因此,软件包com.company.project.tools.uselesscom.company.project.tools完全没有关系。虽然我们人类倾向于以这种方式来组织代码,但可以在这里假设语义关系(这是一件好事),但在技术层面上没有任何关系。与其他两个软件包相比,它们之间没有相对寻址,也没有其他访问权限。实际上,这两个软件包都可以属于两个不同模块的一部分(从Java 9开始),与其他两个名称相似程度较低的软件包相比,它们具有更少的访问权限。

使用另一个包中的类的标准方法是使用com.company.project.Tools.Useless.Foo;,然后在类中使用Foo

目前尚不清楚,您会看到哪个问题,即“导入后将其绑定到当前作用域”是什么意思。 import语句的存在对代码没有影响。它告诉编译器的是如何解决简单名称Foo的出现,如果范围内没有其他Foo的话。

换句话说,本地范围仍然具有优先级,甚至包括继承的成员。此外,在可能出现变量和类型的地方,变量具有优先权。例如。对于Foo.bar()的出现,称为Foo的变量将具有优先权,在相同类型的成员变量,外部类或继承的成员变量之前是局部变量。否则,将使用成员类型,外部类型或继承的成员类型。仅当它们都不存在时,import语句才会用于解析Foo

不用说,您应该避免拥有太多具有相同简单名称的项目,以至于您必须考虑解析过程的细节。这就是为什么命名约定建议以小写字母开头的变量名和以大写字母开头的类名的原因。

是的,请避免为类指定相同的简单名称。一旦必须在同一个编译单元中处理两个类,就无法在整个编译单元中以其(完全¹)限定名称访问其中一个。 (在这种情况下,使用导入*不会对您有任何帮助)


正如所解释的那样,术语“完全”在Java中已过时,因为限定名称总是完整的。