Java导入与代码性能对比

57

我想知道在我的Java程序中包含许多import是否会影响代码的性能(例如,程序会变慢)? Java中import背后的逻辑与C中的include相同吗?

5个回答

83

导入其他模块,会影响代码的性能吗(比如程序变慢)?

不会影响你代码的性能。

导入其他模块并不是通过任何剪切粘贴的机制来实现的,因此二进制文件(类文件)的大小不会增加。它只是一种语法糖,用于避免需要编写冗长的代码,例如:

java.util.List<java.math.BigInteger> myList =
        new java.util.ArrayList<java.math.BigInteger>();

这里有一个小测试,可以证明这一点:

aioobe@e6510:~/tmp$ cat Test.java 
import java.util.*;

public class Test {
    public static void main(String[] args) {
        List<Integer> myInts = new ArrayList<Integer>();
    }
}
aioobe@e6510:~/tmp$ javac Test.java
aioobe@e6510:~/tmp$ md5sum Test.class 
523036e294b17377b4078ea1cb8e7940  Test.class

(修改 Test.java)

aioobe@e6510:~/tmp$ cat Test.java 


public class Test {
    public static void main(String[] args) {
        java.util.List<Integer> myInts = new java.util.ArrayList<Integer>();
    }
}
aioobe@e6510:~/tmp$ javac Test.java
aioobe@e6510:~/tmp$ md5sum Test.class 
523036e294b17377b4078ea1cb8e7940  Test.class

Java中的import和C语言中的include是相同的逻辑吗?

不,#include是一个预处理指令,实现了一个剪切和粘贴的机制。


1
不是要贬低它,但它可以不仅仅是语法糖。 - corsiKa
1
像什么?我的理解是,使用import和不使用import只会在编译器中的IR之前有所不同。(请查看我在更新的答案中的示例。) - aioobe
这基本上就是我一直在回答的问题。在某些情况下(即.*),它可能会增加您的代码编译时间。 - corsiKa
1
@pst,解释一下常量池也足够了。 - bestsss
3
这将是一个更全面回答的不错补充,但很难反驳“位相同的输出”。 - user166390
显示剩余3条评论

24

...这会影响我的代码性能吗?

完全不会。实际上,编译后的类(无论是否使用导入)将是相同的。导入只是一种语法糖,允许您在源代码中使用更短的名称引用外部类或(通过静态导入)类成员。换句话说,它允许您编写:

    Map map = new HashMap();

而不是

    java.util.Map map = new java.util.HashMap();

就这些内容。

在编译时间上可能会有微小的差异。但是,据我所知,例如 import java.util.*; 这样的语句并不会导致编译器加载所有 java.util 的类,而只是将这些类的名字添加到符号表中。

话虽如此:

  • 不必要的导入是一个坏习惯,因为它们会使代码变得混乱,并可能误导阅读代码的人。
  • 通配符导入(.*)可能会导致意外的冲突。
  • 很多人(包括我自己)不喜欢通配符导入,因为他们更愿意看到所使用的实际类的列表。

Java 中的导入逻辑和 C 中的 include 相同吗?

不相同。

C/C++ 的 include 指令将任意的 C/C++ "代码" 注入到源代码流中。这可以包括声明和可执行语句……它们都可以影响性能、执行内存占用和可执行文件大小。


1 - 也就是说,包含文件的作者选择放入文件中的任何内容。它可以是简单的方法和类“签名”,也可以是宏、代码和其他声明,它们都会产生影响。必须检查文件才能确定。


16

这不会对程序的运行速度产生任何影响。

这可能会对程序的编译速度产生影响。

如果你import java.util.*;,它会将整个java.util包加载到编译器中,当你为单个用途.*导入整个包时,可能会增加编译时间(虽然如果这是一个问题,你应该进行一些分析)。

除了可能存在的编译时间问题外,还要考虑可读性问题。通常我(和我交谈过的人)认为import pack.age.Class;import pack.age.*;更易读 - 当然,在做出决定之前请与你的团队进行讨论。

但它的逻辑与#include非常不同,不会膨胀代码。当你包含依赖的jar时,你可能会得到比必需更多的内容,但这可能不是一个大问题。


9
在编写代码时考虑“编译时间速度”似乎不是一个好主意。你可以进行基准测试,查看是否存在任何显著差异,并回来告诉我结果 :-) - aioobe
2
对于速度?是的,我有。http://www.javaperformancetuning.com/news/qotm031.shtml 对于同步?第二个中有一个额外的字节码,因为有一个同步指令,而在第一个中它被烘进了方法修饰符中(理论上可能会影响内联/JIT,但极不可能)。 - corsiKa
2
目前还没有基准测试。如果有的话,那将会很有趣。 - aioobe
3
“can greatly increase the compile time”是一个事实陈述。使用“greatly”还暗示了程度的大小。如果你想将其呈现为需要调查的事项,并不对程度做出任何主张,那么你应该写成“可能会影响编译时间”。这个陈述没有提供足够的证据,可能是错误的。事实不准确是我反对答案的唯一原因,因为误导性的答案比没有回答更糟糕。 - meriton
2
至于帕斯卡没被踩反对票,那是因为他只是声称:“编译器可能需要更长的时间”。 “大大地”比“一点”更多,“可以”比“可能会”的概率更高。顺便说一句,如果你知道那个重复的问题,为什么不把它链接过来呢? - meriton
显示剩余12条评论

2

import不会减慢程序运行速度。最好在不同的packages中拥有不同类型的classes,并根据需要进行导入。这将提高代码的可读性。


你是指“最好将不同种类的类放在不同的包中”是什么意思?谢谢。 - newbie
@新手 我的意思是将不同的类放在不同的包中,并根据需要进行导入,这是一个很好的设计。可能与你的问题没有直接关系。 - fastcodejava

1

导入不是问题。您可以从包中导入您想要的所有内容,代码的执行不会变慢。import 是为了方便,以便您可以使用较短的名称。

当隐式或显式地调用它们的构造函数时(new 操作符),类将被加载。在枚举的情况下,当您在代码中引用枚举名称时,它将被加载。(您可以尝试在枚举的私有构造函数中使用 println 进行实验,并查看何时加载枚举)。 加载类需要时间和内存。一般来说,已加载的类不应该被卸载。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接