猿问

如果对具体类进行更改,是否依赖于接口而不是具体类会减少 Java 中的编译时间?

我正在阅读 Michael Feathers 的“Working Effectively with Legacy Code”,在一个子主题“打破依赖关系”中提到,如果一个类依赖于一个接口,那么如果对具体实现进行了更改,则原始依赖类不会不必再次编译,因为您不直接依赖于实现。

本书章节供参考:https : //www.safaribooksonline.com/library/view/working-effectively-with/0131177052/ch07.html

我同意这一点,但是在 Java 中观察到的这种变化是否在编译时间上有显着差异,或者这在 C++ 的上下文中是否更相关?

我阅读了 C++ 中用于提供编译时优化的 PIMPL 模式或桥接模式,但在 JAVA 中也可以实现相同的功能,还是 Java 编译器自己进行这种优化?


LEATH
浏览 170回答 3
3回答

慕虎7371278

我从未将编译时间视为 Java 中的设计考虑因素(从 v 1 开始使用 Java)。具体到您的问题,语言规范在这方面没有提供任何保证。它可能会因版本和实现而异。在 javac 之外,构建系统可能会做明智的事情,例如参见:https : //blog.gradle.org/incremental-compiler-avoidance编辑:只需仔细检查,即使没有更改,也要javac重新编译源:$ java -versionopenjdk version "10.0.2" 2018-07-17$ javac *.java && ls -l A.*-rw-rw-r-- 1 usr usr 143 Oct 14 20:07 A.class-rw-rw-r-- 1 usr usr  59 Oct 14 19:57 A.java等了一分钟后...$ javac *.java && ls -l A.*-rw-rw-r-- 1 usr usr 143 Oct 14 20:08 A.class-rw-rw-r-- 1 usr usr  59 Oct 14 19:57 A.java

素胚勾勒不出你

不,没有显着差异。大部分编译时间都在解析,这完全不受此影响。重点是:给定文件'MySource.java',包含某种类型的MySource,如果MySource 的任何父类型被重新定义,你真的应该重新编译这个类。你不必,java会尽力而为,但现在你可以创造疯狂的场景(例如,如果你更新父类型来添加一个新的抽象方法,就像一个必须实现的方法,现在你仍然有一个没有的子类型。当您尝试混合由不同的编译运行生成的这些类时,会抛出运行时错误)。使用接口的重点是避免它:即使具体实现确实发生了变化,也有一个根本没有改变的超类型(没有人接触过接口定义)。你会认为这意味着:嘿,太好了,现在我什至不必重新编译这个文件。但这并不重要。与 C 语言相比,java 编译时间非常快(只需几秒钟即可完成大量项目),而且很难有一个足够智能的构建系统来意识到在这种情况下不需要重新编译。不; 关键是有点自我控制:如果你有一个拆分项目,其中接口/父类在源代码库 A 中,而子类在 B 中,事情就会中断:除非 A 和 B 由相同的人维护人和重建同时,你有问题。因此,重点是:您拥有“公共 API”,例如,除非您有充分的理由,否则不得更改您规定的类型。使接口更明确哪些位不会改变。这使源代码库 A 的作者可以自由更改(非公共/导出)实现类,只要他们不弄乱接口,而不必去调用源代码库 B 的优秀人员并告诉他们: 呃,抱歉,我们改变了一些东西,你必须做一个完整的重建。

九州编程

如果更改具体类,则只需要重新编译具体类及其调用者。如果您有一个接口,并且人们正在调用接口而不是具体类,那么他们不会被视为具体类的调用者,也不需要重新编译。这是接口帮助减少编译时间的唯一方法,AFAICT。每个对接口进行类型优化的 Java 实现都将该优化推迟到运行时 (HotSpot) 优化器:有关更多信息,您正在寻找的术语是“专业化”。Java 编译器本身(即:Java => 字节码编译器)实际上几乎没有进行优化,并且由于无法在运行时对代码进行推理(参见:Haskell 的编译器)而受到阻碍。这是因为您可以进行动态代码加载:可以在运行时通过类路径修改和反射来更改接口的可能实现集。
随时随地看视频慕课网APP

相关分类

Java
我要回答