Answers:
唯一的问题是,它会使您的本地名称空间混乱。例如,假设您正在编写Swing应用程序,因此需要它java.awt.Event
,并且还与该公司的日历系统(具有)交互com.mycompany.calendar.Event
。如果同时使用通配符方法导入这两种方法,则会发生以下三种情况之一:
java.awt.Event
和之间存在直接的命名冲突com.mycompany.calendar.Event
,因此甚至无法编译。.*
),但这是错误的,并且您很难弄清楚为什么代码声称类型是错误的。com.mycompany.calendar.Event
,但是当他们以后添加代码时,您先前有效的代码突然停止编译。显式列出所有导入的优点是,我可以一目了然地告诉您要使用哪个类,这使阅读代码变得更加容易。如果您只是快速完成一项操作,那么就没有明显的错误,但是以后的维护人员将非常感谢您的澄清。
这里有一票的明星进口。import语句旨在导入包,而不是类。导入整个包要干净得多。这里标识(如问题java.sql.Date
VS java.util.Date
)很容易通过其他方式弥补,而不是真的通过特定的进口来解决,当然也不能为所有类别的疯狂学步进口辩护。除了打开源文件并分页浏览100条import语句外,没有什么比其他令人不安的了。
进行特定的进口使重构更加困难;如果删除/重命名一个类,则需要删除其所有特定的导入。如果将实现切换到同一包中的其他类,则必须修复导入。尽管这些额外的步骤可以自动执行,但它们实际上是对生产力的打击,没有任何实际收益。
即使Eclipse默认情况下不进行类导入,每个人仍将进行星型导入。很抱歉,但是确实没有合理的理由进行特定的进口。
以下是处理类冲突的方法:
import java.sql.*;
import java.util.*;
import java.sql.Date;
Foo
,并且如果我不使用IDE读取代码(因为您的参数是我不必使用一个),那么我将如何知道哪个软件包Foo
来自?当然,使用IDE,IDE会告诉我,但是您的整个论点是,我应该能够不带任何代码地阅读代码。进行显式导入有助于记录代码 (避免使用通配符的主要原因),与不使用IDE 编写代码相比,不使用IDE 读取代码的可能性更大。
请参阅我的文章按需导入是邪恶的
简而言之,最大的问题是,将类添加到导入的包时,代码可能会中断。例如:
import java.awt.*;
import java.util.*;
// ...
List list;
在Java 1.1中,这很好。列表在java.awt中找到,没有冲突。
现在,假设您签入了运行良好的代码,一年后,其他人将其带出进行编辑,并使用Java 1.2。
Java 1.2在java.util中添加了一个名为List的接口。繁荣!冲突。完美工作的代码不再起作用。
这是一种EVIL语言功能。有否原因,代码应该停止编译仅仅因为一个类型添加到包...
另外,这使读者很难确定您正在使用哪个“ Foo”。
java.util.List
vs还算java.awt.List
不错,但是当类名是Configuration
多个依赖库已经在其最新的maven repo版本中添加了它时,请尝试一下。
这不是不好用通配符与Java导入语句。
在Clean Code中,Robert C. Martin实际上建议使用它们以避免冗长的导入列表。
这是建议:
J1:通过使用通配符避免长导入列表
如果您使用一个包中的两个或多个类,请使用
进口包裹。*;
一长串的进口商品对读者来说是艰巨的。我们不想让80条进口的商品杂乱无章。相反,我们希望导入内容是与我们合作的软件包的简要说明。
特定的导入是硬依赖性,而通配符导入则不是。如果专门导入一个类,则该类必须存在。但是,如果您导入带有通配符的软件包,则不需要存在任何特定的类。当寻找名称时,import语句只是将包添加到搜索路径中。因此,此类导入不会创建真正的依赖关系,因此它们可保持模块之间的耦合性降低。
有时候,一长串的特定进口商品可能会有用。例如,如果您正在处理旧版代码,并且想要找出构建模拟和存根所需的类,则可以在特定导入列表中查找所有这些类的真实限定名称,然后放入适当的存根。但是,这种用于特定进口的用途非常少见。此外,大多数现代IDE都允许您使用单个命令将通配符导入转换为特定导入列表。因此,即使在传统情况下,也最好导入通配符。
导入通配符有时会导致名称冲突和歧义。具有相同名称但包装不同的两个类将需要特别导入,或者至少在使用时特别限定。这可能很麻烦,但非常罕见,以至于使用通配符导入通常仍然比特定的导入要好。
性能:字节码相同对性能没有影响。尽管这会导致一些编译开销。
编译:在我的个人计算机上,不输入任何内容即可编译空白类需要100毫秒,而导入java。*时要花费170毫秒是同一个类。
import java.*
什么都不进口。为什么会有所作为?
我工作过的大多数地方都使用大量Java,使显式导入成为编码标准的一部分。在生产代码时,有时我仍使用*进行快速原型制作,然后扩展导入列表(某些IDE也会为您完成此操作)。
这对运行时没有影响,因为编译器会自动将*替换为具体的类名。如果您反编译.class文件,您将永远看不到import ...*
。
C#始终使用*(隐式),因为您只能使用using
包名称。您绝对不能指定类名。Java在c#之后引入了该功能。(Java在许多方面都非常棘手,但这超出了本主题)。
在Intellij Idea中,当您执行“组织导入”时,它将自动用*替换同一软件包的多个导入。这是一项强制性功能,因为您无法将其关闭(尽管可以增加阈值)。
接受的回复列出的案例无效。没有*,您仍然遇到相同的问题。无论是否使用*,都需要在代码中指定包装名称。
记录:添加导入时,还表示您的依赖项。
您可以快速看到文件的依赖关系(不包括相同命名空间的类)。
最重要的是,导入java.awt.*
会使您的程序与将来的Java版本不兼容:
假设您有一个名为“ ABC”的类,您正在使用JDK 8并导入了java.util.*
。现在,假设Java 9出现了,并且它在软件包java.util
中有一个新类,巧合的是,它也恰好被称为“ ABC”。您的程序现在将无法在Java 9上编译,因为编译器不知道名称为“ ABC”的意思是您自己的类还是中的新类java.awt
。
仅从java.awt
实际使用的类中显式导入那些类时,就不会有此问题。
资源:
Stream
作为Java 8中java.util中Java中添加的新类的示例...
在双方提出的所有有效观点中,我还没有找到避免使用通配符的主要原因:我喜欢能够阅读代码并直接知道每个类是什么,或者它的定义是否不是语言或语言。文件,在哪里找到它。如果使用*导入了多个包,则必须搜索其中的每个包以找到我不认识的类。可读性是至高无上的,我同意代码不应要求使用IDE来读取它。