1

首先,我不是 Java 人,但我发现表面上看起来与导入的工作方式不一致。

假设你有一个文件,在这个文件中你有你的 main 函数,并且你还定义了一个类Foo,现在一个不同的Foo实现也存在于一个包中。假设您想在您的功能中使用这两个版本。

您不能从它的包中显式导入Foo,即import mypackage.Foo;

由于这将导致与文件中本地定义的类发生冲突,因此在编译时会产生错误。

可以做的是导入整个包,即import mypackage.*;

这将起作用,您可以使用完全限定名称访问Foo,使用简单名称将导致使用本地Foo。我看到的不一致之处在于,虽然前者会产生错误(您已经导入了一个类,并且导入的唯一目的是能够使用简单名称而不是完全限定名称),但后者甚至不会导致警告.

我原以为这两种情况都会产生警告,即您可能使用了错误的类,因为它在 2 个地方定义,或者 import 语句是多余的,因为使用简单名称将解析为本地定义的类,而不是导入的一。

所以我的问题是:以这种方式实施是否有根本原因?

是的,这是一个异常情况,我明白这一点。

4

4 回答 4

9

即使不导入 mypackage.*,您也可以使用完全限定名称访问 Foo;

关于警告:我想没有什么危险的事情发生。你没有使用任何模棱两可的东西。

于 2009-05-13T08:45:42.020 回答
3

Foo正如上面的答案所说,导入实际上对另一个包中的没有任何作用;无论您是否导入,都不能通过短类名引用其他 Foo ,您可以通过完全限定的类名引用它。

从概念上讲,您import mypackage.*不一定可以将其视为“从“导入所有类mypackage”,而可​​以认为“从“导入所有非冲突类mypackage”。我不知道 Sun 的编译器实现是如何做到的,但它肯定会决定不匹配 mypackage.Foo 作为通配符的一部分(因此根本不导入它),并且代码将以任何方式工作。

导入实际上只是设置一个从短类名到完全限定类名的别名(例如,当我说Date解释为时java.util.Date)。如果你做了一些完全多余的事情,比如只导入冲突的类,你会收到警告。但是,如果您使用 拉入整个包*,编译器抱怨其中一个类名发生冲突对我来说似乎是错误的。这在实践中经常发生,并且在 99% 以上的情况下都是无害的,以至于它会产生“狼来了的男孩”综合症,以至于你不太可能注意这些和其他警告,因为你只是习惯被他们轰炸。

顺便说一句,如果你同时导入java.util.*and java.sql.*,这是允许的,它本身不会导致任何警告;但是,如果您尝试仅引用Date(在本地包中没有这样的类),您将收到编译错误,因为名称不明确。

于 2009-05-13T09:17:16.087 回答
1

您可以将“import p.*”视为“当您无法解析当前文件中的名称时,尝试在包 p 中解析它”。编译器在看到 import 语句时不会导入p中的所有内容。相反,当它找到一个在直接编译单元中无法解析的名称时,它会在p (以及 import ...* 语句中命名的其他包)中查找。

于 2009-05-13T11:21:51.920 回答
1

对于 mypackage 中的所有其他内容,import mypackage.* 可能是必需的。如果有警告,则根本很难避免,即您必须完全限定您在 mypackage 中使用的所有其他类等。更糟糕的是,考虑 mypackage 版本 1 不包含 Foo 的情况,因此没有冲突,因此根本没有理由发出警告。版本 2 包含 Foo,但它当然不是您要在程序中访问的 Foo。因此,如果编译器警告“import package.*”冲突,它会使“import package.*”潜在地降低向上兼容性。

于 2009-05-13T09:16:04.607 回答