使用像
这样的单一语句会更方便,更清晰import java.awt.*;
而不是导入一堆单独的类
import java.awt.Panel;
import java.awt.Graphics;
import java.awt.Canvas;
...
在import
声明中使用通配符有什么问题?
答案 0 :(得分:435)
它唯一的问题是它使你的本地命名空间变得混乱。例如,假设您正在编写Swing应用程序,因此需要java.awt.Event
,并且还要与公司的日历系统({1}}连接。如果使用通配符方法导入两者,则会发生以下三种情况之一:
com.mycompany.calendar.Event
和java.awt.Event
之间存在直接的命名冲突,因此您甚至无法编译。com.mycompany.calendar.Event
),但这是错误的,并且您很难弄清楚为什么您的代码声称类型错误。.*
,但是当他们稍后添加一个时,您之前有效的代码会突然停止编译。明确列出所有导入的优点是,我可以一目了然地告诉您要使用哪个类,这使得阅读代码变得更加容易。如果你只是做一个快速的一次性事情,没有明确的错误,但未来的维护者会感谢你的清晰度。
答案 1 :(得分:165)
这是对明星导入的投票。 import语句旨在导入包,而不是类。导入整个包更干净;此处确定的问题(例如java.sql.Date
vs java.util.Date
)很容易通过其他方式补救,而不是通过特定进口解决真正,并且肯定不能证明所有类别的疯狂迂腐进口。没有什么比打开源文件和翻阅100个导入语句更令人不安了。
进行特定的导入会使重构变得更加困难;如果您删除/重命名某个类,则需要删除其特定导入的所有。如果将实现切换到同一个包中的其他类,则必须修复导入。虽然这些额外的步骤可以实现自动化,但它们确实可以提高工作效率。
即使Eclipse默认不进行类导入,每个人仍然会进行星级导入。对不起,但是进行特定进口确实没有合理的理由。
以下是如何处理类冲突:
import java.sql.*;
import java.util.*;
import java.sql.Date;
答案 2 :(得分:150)
请参阅我的文章Import on Demand is Evil
简而言之,最大的问题是当一个类添加到您导入的包时,您的代码可能会中断。例如:
import java.awt.*;
import java.util.*;
// ...
List list;
在Java 1.1中,这很好;列表在java.awt中找到并且没有冲突。
现在假设您签入了完美的代码,一年后其他人将其编辑出来进行编辑,并使用Java 1.2。
Java 1.2在java.util中添加了一个名为List的接口。繁荣!冲突。完美的代码不再有效。
这是 EVIL 语言功能。 NO 原因是代码应该停止编译,因为类型已添加到包...
此外,它使读者难以确定您正在使用哪个“Foo”。
答案 3 :(得分:63)
使用带有Java导入语句的通配符不不好。
在Clean Code中,Robert C. Martin实际上建议使用它们来避免长导入列表。
以下是建议:
J1:使用避免长导入列表 通配符
如果您使用两个或多个类 包,然后导入整个包 与
导入包。*;
很长的进口清单令人望而生畏 读者。我们不想杂乱 我们模块的顶部有80个 进口线。相反,我们想要的 进口是一个简明的陈述 关于我们合作的软件包 用。
特定进口很难 依赖关系,而通配符导入 不是。如果你专门导入一个 class,那个类必须存在。但 如果你导入一个包 通配符,没有特定的类需要 存在。简单的import语句 将包添加到搜索路径 在寻找名字的时候。所以不是真的 依赖是由这样的导入创建的, 因此他们有助于保持我们的 模块较少耦合。
有时会列出长名单 具体的进口可能很有用。对于 例如,如果你正在处理 遗留代码,你想知道 你需要什么类来建立模拟 和存根,你可以走下去 要找出的具体进口清单 所有这些的真正合格的名字 然后把类放到适当的位置 存根到位。但是,这个用途 具体进口非常罕见。 此外,大多数现代IDE都会 允许你转换通配符 导入到特定导入列表 用一个命令。所以即使在 遗留案例最好导入 通配符。
通配符导入有时会导致 命名冲突和含糊不清。二 具有相同名称的类,但在 不同的包,将需要 特别是进口,或至少 使用时特别合格。这个 可能是一件令人讨厌但很少见的事情 使用通配符导入仍然是 一般比具体要好 进口。
答案 4 :(得分:22)
它使您的命名空间变得混乱,要求您完全指定任何不明确的类名。最常见的情况是:
import java.util.*;
import java.awt.*;
...
List blah; // Ambiguous, needs to be qualified.
它还有助于使您的依赖项具体化,因为所有依赖项都列在文件的顶部。
答案 5 :(得分:20)
性能:由于字节代码相同,因此对性能没有影响。 虽然这会导致一些编译开销。
编译:在我的个人计算机上,编译空白类而不导入任何内容需要100毫秒,但导入java时相同的类。*需要170毫秒。
答案 6 :(得分:14)
我工作过的大多数使用大量Java的地方都使得显式导入成为编码标准的一部分。我有时仍然使用*来进行快速原型设计,然后在产品化代码时扩展导入列表(一些IDE也会为你做这个)。
答案 7 :(得分:10)
我更喜欢特定的导入,因为它允许我在不查看整个文件的情况下查看文件中使用的所有外部引用。 (是的,我知道它不一定会显示完全合格的参考文献。但我尽可能避免使用它们。)
答案 8 :(得分:9)
在之前的项目中,我发现从* -imports更改为特定导入会将编译时间缩短一半(从大约10分钟缩短到大约5分钟)。 * -import使编译器搜索列出的每个包中与您使用的类匹配的类。虽然这个时间可能很短,但它会增加大型项目。
* -import的副作用是开发人员会复制并粘贴常用的导入行,而不是考虑他们需要的内容。
答案 9 :(得分:6)
在实施将基于的任何开发技术中,寻找最小化的方法 重构MODULES的工作。在Java中,没有逃避导入到单个类,但你 至少可以一次导入整个包裹,反映出包装是高度凝聚力的单位的意图 同时减少更改包名称的工作量。
如果它使本地命名空间变得混乱,那不是你的错 - 责怪包的大小。
答案 10 :(得分:2)
最重要的一点是导入java.awt.*
可能会使您的程序与未来的Java版本不兼容:
假设您有一个名为" ABC"的类,您正在使用JDK 8并导入java.util.*
。现在,假设Java 9出现了,它在包java.util
中有一个新类,巧合也恰好被称为" ABC"。您的程序现在不能在Java 9上编译,因为编译器不知道是否使用名称" ABC"你的意思是你自己的班级或java.awt
中的新班级。
当您从实际使用的java.awt
明确导入这些类时,您不会遇到此问题。
资源:
答案 11 :(得分:2)
在双方的所有有效观点中,我没有找到避免使用通配符的主要原因:我希望能够阅读代码并直接知道每个类是什么,或者它的定义是不是语言或文件,在哪里找到它。如果使用*导入多个包,我必须搜索每个包以找到我无法识别的类。可读性是至关重要的,我同意代码不应该要求 IDE来阅读它。
答案 12 :(得分:2)
没有运行时影响,因为编译器会自动用具体的类名替换*。如果您反编译.class文件,您将永远不会看到import ...*
。
C#始终使用*(隐式),因为您只能using
包名称。你永远不能指定类名。 Java在c#之后引入了这个特性。 (Java在很多方面都很棘手,但它超出了这个主题)。
在Intellij Idea中,当您执行“组织导入”时,它会自动使用*替换同一个包的多个导入。这是一项强制性功能,因为您无法将其关闭(尽管您可以提高阈值)。
接受回复列出的案例无效。没有*你仍然有同样的问题。无论您是否使用*,都需要在代码中指定pakcage名称。
答案 13 :(得分:2)
以下是有关该主题的一些发现。
在编译期间,编译器尝试从。*导入中查找代码中使用的类,并且通过从。*导入中选择使用的类来生成相应的字节代码。因此,由于使用相同的字节码,因此使用。* import或.class名称import的字节码将相同,并且运行时性能也将相同。
在每个编译中,编译器必须扫描。*包的所有类以匹配代码中实际使用的类。因此,与使用.class名称导入相比,带有。* import的代码在编译过程中花费更多的时间。
使用。*导入有助于使代码更简洁
使用。*导入会在我们使用来自两个不同程序包的两个同名类时产生歧义。例如,日期在两个软件包中均可用。
import java.util.*;
import java.sql.*;
public class DateDemo {
private Date utilDate;
private Date sqlDate;
}
答案 14 :(得分:1)
忘记混乱的名称空间...,考虑一下可怜的人,他们必须在vi,Notepad ++或其他非IDE文本编辑器中的GitHub上阅读和理解您的代码。
该人必须仔细检查每个通配符范围内所有通配符的所有类和引用中来自通配符之一的每个令牌……只是要弄清楚到底发生了什么。
如果您只为编译器编写代码-并且您知道自己在做什么-我确定通配符没有问题。
但是,如果其他人(包括您将来的人)希望在阅读时快速理解特定的代码文件,那么显式引用会很有帮助。
答案 15 :(得分:0)
记录: 添加导入时,还表示您的依赖项。
您可以快速查看文件的依赖关系(不包括相同命名空间的类)。
答案 16 :(得分:0)
将所有类导入包中被认为是盲目的方法。造成这种情况的主要原因是,它会使类名称空间混乱,并可能导致具有相同名称的不同包中的类之间发生冲突。
专门填充必要的类可以避免该问题,并清楚地显示所需的版本。这对代码的可维护性很有帮助。