【问题标题】:importing classes using wildcards使用通配符导入类
【发布时间】:2013-05-30 05:30:21
【问题描述】:

如果我说:

import java.awt.event.ActionListener;

我得到了 ActionListener 类。 如果我说:

import java.awt.event.*;

我得到了事件类包括 ActionListener? 或者更好:

import java.awt.*;

我认为如果你包含一个类,就像在最后两个示例中一样,你有效地导入了该类并继承了它的所有子类。但是,例如,当我只使用最后一行时,Eclipse 经常显示错误,说它无法解析某些项目,并建议我包含 both java.awt 和 java.awt.event。

【问题讨论】:

  • 使用import java.awt.* 将只导入java.awt 包中的类(如果有)。请注意,* 通配符不是每个包的递归。
  • 您的最后两个示例不“包含类”,它们导入包。

标签: java class import


【解决方案1】:

Java 中的“通配符”导入仅适用于实现类的直接级别。

也就是说,如果您有类 ABC,并且具有完全限定名称:

  • com.foo.bar.A;
  • com.foo.bar.B;
  • com.foo.C;

然后导入com.foo.bar.* 将允许访问AB,无需多言;但C 将不可用。

同样,导入com.foo.* 将很容易获得C,但不是AB

现在:

我认为如果您包含一个类,就像在上两个示例中一样,您有效地导入了该类并继承了它的所有子类。

它没有。即使B“继承”A,如果您选择使用完全限定导入com.foo.bar.A,它也不会自动导入com.foo.bar.B。您必须单独导入B。这是有道理的:没有什么会强制接口或抽象类的实现与其基接口/基类在同一个包中,例如;在同一个项目中,你可能有两个名为B的类,在不同的包中:编译器应该做什么?

现在,根据编码风格约定,你要么自己弥补,要么必须在工作环境中遵守,这样的通配符导入可能是完全禁止的,你必须导入 A 和 @987654342 @ 分别地。至于静态导入,他们还有其他问题......

最后,请注意,默认情况下,您可以使用所有 java.lang.* 而无需声明导入。

【讨论】:

  • 我明白了。谢谢你。无论如何要按照我描述的方式导入?
  • 好的,我明白了。如果在这里,B 扩展了 A,那么 import com.foo.bar.A; 将不会让您访问 B。您必须单独导入 B。这是有道理的:没有什么会强制接口或抽象类的实现与其基接口/基类在同一个包中(幸运的是!)(相应地编辑了答案)
【解决方案2】:

java.awt.*java.awt.event.*不同,第一个会导入java.awt包内的所有类,而第二个会导入java.awt.event内的所有类,import函数只会导入类,不会包。

【讨论】:

    【解决方案3】:

    来自 Java 教程:Apparent Hierarchies of Packages

    起初,包似乎是分层的,但实际上并非如此。例如,Java API 包括 java.awt 包、java.awt.color 包、java.awt.font 包以及许多其他以 java.awt 开头的包。但是,java.awt.color 包、java.awt.font 包和其他java.awt.xxxx 包不包含在java.awt 包中。前缀java.awt(Java Abstract Window Toolkit)用于许多相关的包以使关系明显,但不显示包含。

    导入java.awt.* 会导入java.awt 包中的所有类型,但不会导入java.awt.colorjava.awt.font 或任何其他java.awt.xxxx 包。如果您打算使用 java.awt.color 以及 java.awt 中的类和其他类型,则必须导入这两个包及其所有文件:

    import java.awt.*;

    import java.awt.color.*;

    【讨论】:

      【解决方案4】:

      请记住,import 语句只是为了方便。它使您可以使用类的短名称而不是完全限定名称。

      Java 中的包名结构对应一个目录结构。所以你可以把它想象成一个名为 java 的目录,在这个目录中还有其他几个目录,比如 awt 和 io 等。

      当你说

      import java.awt.*;
      

      您基本上是说您想为 java.util.java 目录中名为 awt 的目录中的所有类使用短名称。因此,如果您在代码中使用这样的类名:

         List mylist;
      

      然后编译器将尝试在当前包中查找名为 List 的类或名为 java.awt.List 的类。

      因此,如果您在 awt 目录中有一个名为 event 的目录,并且在该目录中有一个名为 ActionEvent 的类,则完全限定名称为:

        java.awt.event.ActionEvent
      

      上面的 import 语句没有帮助。因此需要另一个导入语句的原因

        import java.awt.event.*;
      

      现在,如果您使用 ActionEvent 类,编译器会在当前目录或 java.awt.ActionEvent 或 java.awt.event.ActionEvent 中查找名为 ActionEvent 的类,直到找到为止。

      【讨论】:

        【解决方案5】:

        来自 Sun 在 Using Package Members 上的文档:

        起初,包似乎是分层的,但实际上并非如此。例如,Java API 包括一个 java.awt 包、一个 java.awt.color 包、一个 java.awt.font 包,以及许多其他以 java.awt 开头的包。 但是,java.awt.color 包、java.awt.font 包和 java.awt 包中不包含其他 java.awt.xxxx 包。 前缀 java.awt(Java 抽象窗口工具包)用于 相关包的数量以使关系明显,但不是 显示包容性。

        导入 java.awt.* 导入 java.awt 包中的所有类型, 但它不导入 java.awt.color、java.awt.font 或任何其他 java.awt.xxxx 包。如果您打算使用类和其他类型 在 java.awt.color 和 java.awt 中,你必须同时导入 包含所有文件的软件包:

        import java.awt.*; 
        import java.awt.color.*;
        

        如果你有时间,你可能会好好阅读来自 sun 的 the entire Packages trail,它彻底地介绍了基础知识和更复杂的概念。从您问题中的语言来看,您将第二个 import 语句称为包含特定类,听起来您并不理解您实际上是在指代包。

        【讨论】:

        • 课程包?我把我的行话弄混了。几天前开始从 C 开始 java。
        • “我得到了包含 ActionListener 的事件类?或者更好:”子类。”如果你把你的行话弄混了,那很好,但是这些句子让你看起来真的像你最初将包称为类。