Eclipse / Java – 导入java是否有害。(命名空间)。*?

为什么Eclipse在导入类型时会采用细粒度的方法? 在C#中,我习惯于使用“使用System.Windows.Controls”并完成它,但Eclipse更喜欢导入我单独引用的每个小部件(使用Ctrl + Shift + O快捷方式)。 如果我知道我需要多个类型,导入整个命名空间会有什么危害吗?

如果多个包中存在多个具有相同名称的类,则通配符包导入可能导致的唯一损害是命名空间冲突的可能性增加。

比如说,我想编程在AWT应用程序中使用Java Collections Framework的ArrayList类,该应用程序使用List GUI组件来显示信息。 为了举个例子,我们假设我们有以下内容:

 // 'ArrayList' from java.util ArrayList strings = new ArrayList(); // ... // 'List' from java.awt List listComponent = new List() 

现在,为了使用上述内容,必须对这两个类进行导入,最低限度:

 import java.awt.List; import java.util.ArrayList; 

现在,如果我们在包import使用通配符,我们将拥有以下内容。

 import java.awt.*; import java.util.*; 

但是,现在我们会遇到问题!

有一个java.awt.List类和一个java.util.List ,因此引用List类将是不明确的。 如果我们想要消除歧义,则必须使用完全限定的类名称引用List

 import java.awt.*; import java.util.*; ArrayList strings = new ArrayList(); // ... // 'List' from java.awt -- need to use a fully-qualified class name. java.awt.List listComponent = new java.awt.List() 

因此,有些情况下使用通配符包import会导致问题。

Eclipse在Window – > Preferences对话框中有一个很棒的设置叫做“Organize Imports”,可以让你说当从包中使用N个类时,进行通配符导入。 我通常在N = 2或3时使用它。

有人可以在没有IDE的情况下读取您的代码 – 在这种情况下,非通配符导入将帮助他找出代码中使用的类。

import指令是一个编译器指令,它告诉编译器在哪里查找类,并且不必总是使用完全限定的类名,例如java.util.HashMap 。 但是import指令本身并没有放入已编译的字节码文件中,编译器会将完全限定的名称编译到.class文件中。

当使用没有通配符时,该指令显式地告诉编译器在类路径中查找一个特定文件。 使用通配符,该指令告诉编译器查找命名包在每次需要匹配任何名称时在该包中搜索可能的匹配项。 对于编译器而言,后一版本可能比前者更长一些。

换句话说, import指令不会以任何方式影响运行时代码的执行。 但是, import指令确实会影响编译时间。 另外,我发现使用带通配符的import会降低代码的可读性。

实际上, javaperformancetuning.com上的月份import报表成本问题在其结论中完美地总结了这一点:

  • 使用import语句没有运行时成本
  • 使用import语句,编译过程可能需要更多时间
  • 使用通配符import语句,编译过程可能需要更多时间
  • 为了提高可读性,通配符导入语句对于除了一次性类之外的任何东西都是不好的做法
  • 非通配符导入语句的编译开销很小,但它们提供了可读性优势,因此最佳实践是使用它们

我不相信通配符导入会产生任何性能影响(如果确实如此,我认为它只会在编译时发生)。 但正如这篇SOpost指出的那样 ,如果你使用它们,你可能会有类名称重叠。

当我使用尚未导入的类时,我只使用Ctrl + Space强制导入,导入会自动进行。 然后,在重构类以删除任何不再使用的导入后,我按Ctrl + Shift + O.

直到JDK 1.2,这段代码编译正常:

 import java.awt.*; import java.util.*; public class Foo { // List is java.awt.List private List list; } 

在JDK 1.2中添加了java.util.List并且代码不再编译,因为编译器不知道想要哪个List(awt或util)。 您可以通过添加“import java.awt.List;”来修复它。 在import的最后,但重点是你必须做一些事情来解决它。

我个人使用单一导入而不是按需导入有两个原因:

  1. 很明显每个class级来自哪里
  2. 如果你有大量的import,这个类可能做得太多,应该分开。 这是一种“代码味道”。

从纯粹主义的角度来看,每次import都会产生依赖性和冲突的可能性。 import被视为必要的邪恶,因此它们被最小化。 使用*导入另一个包就像写一个空白支票。 导入这样的两个软件包就像让某人在您的帐户之间移动资金一样。

从实际的角度来看,这通常是有意义的,因为不同的项目和库对于不同的概念使用惊人相似的名称。 或者,假设您从包A导入所有内容,然后从包B导入所有内容,并使用包B中的某些类C.如果稍后有人将包含名称C的类添加到包A,则代码可能会中断!

话虽如此,我承认我很懒。 我经常会预先导入包中的所有内容,然后让Eclipse根据我实际使用的内容为我组织它。

导入包/名称空间中的所有类没有坏处,但我认为最好包含每个单独的类。 这使得开发人员更清楚地了解每个class级来自哪个开发人员。

如果你使用像IntelliJ这样function强大的IDE,那么这不是问题。 我认为Eclipse和NetBeans也可以管理导入。 它将为您添加代码并从视图中折叠它们,这样它们就不会使窗口混乱。 什么可以更容易?

不伤害代码。 作为一般原则,为什么要输入一些东西,如果你不打算使用?

如果你写一些java代码,如

 LinkedList llist = new LinkedList() 

如果您没有将LinkedList导入项目,Eclipse会询问您是否要导入它。 由于您只使用LinkedList而没有其他内容,因此它只会导入LinkedList。 如果你在同一个项目中做了其他事情,比如
ArrayList alist = new ArrayList()

然后Eclipse也会说你需要导入ArrayList,但没有别的。 Eclipse只根据您所做的任何库调用导入所需的内容。 如果您需要来自同一个库的多个类型或项目,则使用a无害

import java.namespace.*

继续并带来你需要的其他物品。 只要您导入包含您引用的项目的包和库,Eclipse就不会在意,例如Scanners,LinkedLists等。

从可读性的角度来看,这是一个不同的问题。 如果您希望人们明确知道您要导入的内容,则可能需要调用每个小部件或包。 如果您在标准库中使用来自同一个包的许多不同函数,并且可以使您的文件头很长,那么这可能会变得相当繁琐。*通配符。 通过通配符导入没有任何害处,它实际上归结为您的编码标准以及您希望类标题的透明度。

显式导入每个类在短名称(例如代理)和长名称(例如java.lang.reflect.Proxy)之间提供硬绑定,而不是松散绑定,表示java.lang.reflect.*可能存在一个java.lang.reflect.*java.io.*java.net.*或您拥有的通配符导入的其他位置。

如果由于某种原因, 另一个名为Proxy的类出现在java.io.*java.net.*或您自己的代码中,那么这可能是一个问题,因为编译器然后不知道您想要哪个Proxy类。如果您显式导入了java.lang.reflect.Proxy。

以上示例不具备条件。 java.net中引入了java.net.Proxy类,如果它是按照上面的提示编写的话,它会破坏你的代码。 请参阅http://java.sun.com/j2se/1.5.0/compatibility.html上有关如何规避通配符问题的Sun官方解释。

(对于那些不使用IDE来维护import语句的人来说,通配符导入只是一种便利机制。如果你使用IDE,那就让它帮你:)