简介
从 C++ 迁移过来,最大的区别之一是作用域的不同:在 C++ 中,每个标识符都相对于当前作用域(class
或 namespace
),您可以在开头编写一个带有范围解析运算符 ::
的绝对路径。
但是,在 Java 中,我无法找到一种方法来访问其他包中的标识符,而不将其导入到当前作用域或写入其完整路径。
如果我有几个同名的类,这可能会是一个问题(然后,在 C++ 中,我会将它们称为 Module1::Foo 和 Module2::Foo,只要我愿意,这在 Java 中是不可能的)保存我的理智,因为 com.company.project.module1.Foo
对我来说太长了)。
代码!
以下是从 Java 和 C++ 访问类 Tools.Useless.Foo
的示例(没有 import
或 using
)
工具/Useless/Foo.hpp
:
namespace Tools {
namespace Useless {
class Foo {
};
}
}
工具/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;
...
问题
- 有没有办法从包
Tools.Useless
访问Foo
而不指定Tools.Useless
完整包名称(并导入它;因为导入它会将其绑定(bind)到当前作用域)? - 我做得对吗?我应该如何使用几个同名的类?我应该避免这种情况,还是直接用“package.*”导入它们来绕过它?
解决方案
- 使用更多包描述性类名(例如
ToolsUselessFoo
而不仅仅是Foo
)。 - 使用
import path.to.module.*
而不是import path.to.module.Foo
导入所有内容,然后访问Foo
解决任何歧义所需的包。问题是有时包名称具有含义(例如Tools.Useless.Foo
和Tools.Useful.Foo
)。
最佳答案
Java 包不嵌套。虽然它们的名称可能具有共同的前缀,但这在 Java 编程语言中没有任何意义。
此外,当存储是文件系统时,它们的类文件存储在嵌套目录中,这一事实没有其他意义。当类存储在 jar 文件中时,它们的存储条目名称与其限定名称相匹配,而根本不实际形成目录(尽管很多工具喜欢将它们呈现为分层结构以模仿文件系统)。
所以包com.company.project.tools.useless
和com.company.project.tools
根本没有关系。虽然我们人类倾向于以这样的方式组织代码,但这里可以假设语义关系(这是一件好事),但在技术层面上却没有。与任何其他两个包相比,它们之间没有相对寻址,也没有额外的访问权限。事实上,这两个包都可以是两个不同模块的一部分(从 Java 9 开始),与其他两个名称不太相似的包相比,访问权限甚至更少。
使用另一个包中的类的标准方法是使用 import com.company.project.Tools.Useless.Foo;
,然后在其中使用 Foo
类(class)。
目前还不清楚您看到了什么问题,即“自从导入它会将其绑定(bind)到当前作用域”应该意味着什么。 import
语句的存在对代码没有任何影响。它告诉编译器,如果范围内没有其他 Foo
,如何解析简单名称 Foo
的出现。
换句话说,本地作用域仍然具有优先级,即使包括继承的成员。此外,在变量和类型可能出现的地方,变量具有优先权。例如。对于 Foo.bar()
的出现,名为 Foo
的变量具有优先权,局部变量优先于同一类型、外部类或继承类中的成员变量。否则,将使用成员类型、外部类型或继承的成员类型。仅当它们都不存在时,import
语句才会用于解析 Foo
。
不用说,您应该避免有太多具有相同简单名称的项目,否则您将不得不考虑解析过程的细节。这就是为什么命名约定建议变量名以小写字母开头,类名以大写字母开头。
是的,避免为类指定相同的简单名称。一旦您必须在同一编译单元中处理这两个类,就无法在整个编译单元中使用其(完全)限定名称来访问其中一个类。 (在导入中使用 *
对这种情况没有任何帮助)
正如所解释的,术语“完全”在 Java 中已经过时,因为限定名称始终是完整的。
关于java - Java 中包相对标识符路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51162872/