编译时与运行时依赖 - Java
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4270950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compile time vs Run time Dependency - Java
提问by Kunal
What is the difference between compile time and run time dependencies in Java? It is related to class path, but how do they differ?
Java 中的编译时和运行时依赖项有什么区别?它与类路径有关,但它们有何不同?
回答by Jason S
The compiler needs the right classpath in order to compile calls to a library (compile time dependencies)
编译器需要正确的类路径才能编译对库的调用(编译时依赖)
The JVM needs the right classpath in order to load the classes in the library you are calling (runtime dependencies).
JVM 需要正确的类路径才能加载您正在调用的库中的类(运行时依赖项)。
They may be different in a couple of ways:
它们可能在几个方面有所不同:
1) if your class C1 calls library class L1, and L1 calls library class L2, then C1 has a runtime dependency on L1 and L2, but only a compile time dependency on L1.
1) 如果您的类 C1 调用库类 L1,而 L1 调用库类 L2,则 C1 对 L1 和 L2 具有运行时依赖性,但仅对 L1 具有编译时依赖性。
2) if your class C1 dynamically instantiates an interface I1 using Class.forName() or some other mechanism, and the implementing class for interface I1 is class L1, then C1 has a runtime dependency on I1 and L1, but only a compile time dependency on I1.
2) 如果您的类 C1 使用 Class.forName() 或其他某种机制动态实例化接口 I1,并且接口 I1 的实现类是类 L1,则 C1 对 I1 和 L1 具有运行时依赖性,但只有编译时依赖性在 I1。
Other "indirect" dependencies which are the same for compile-time and run-time:
编译时和运行时相同的其他“间接”依赖项:
3) your class C1 extends library class L1, and L1 implements interface I1 and extends library class L2: C1 has a compile-time dependency on L1, L2, and I1.
3) 您的类 C1 扩展了库类 L1,而 L1 实现了接口 I1 并扩展了库类 L2:C1 对 L1、L2 和 I1 具有编译时依赖性。
4) your class C1 has a method foo(I1 i1)
and a method bar(L1 l1)
where I1 is an interface and L1 is a class that takes a parameter which is interface I1: C1 has a compile-time dependency on I1 and L1.
4) 你的类 C1 有一个方法foo(I1 i1)
和一个方法bar(L1 l1)
,其中 I1 是一个接口,L1 是一个类,它接受一个接口 I1 的参数:C1 对 I1 和 L1 有编译时依赖。
Basically, to do anything interesting, your class needs to interface with other classes and interfaces in the classpath. The class/interface graph formed by that set of library interfacesyields the compile-time dependency chain. The library implementationsyield the run-time dependency chain.Note that the run-time dependency chain is run-time dependent or fail-slow: if the implementation of L1 sometimes depends on instantiating an object of class L2, and that class only gets instantiated in one particular scenario, then there's no dependency except in that scenario.
基本上,要做任何有趣的事情,您的类需要与类路径中的其他类和接口进行交互。由那组库接口形成的类/接口图产生编译时依赖链。库实现产生运行时依赖链。请注意,运行时依赖链是运行时依赖或失败缓慢的:如果 L1 的实现有时依赖于实例化类 L2 的对象,并且该类仅在一个特定场景中被实例化,那么除了在那个场景。
回答by JOTN
Java doesn't actually link anything at compile time. It only verifies the syntax using the matching classes it finds in the CLASSPATH. It's not until runtime that everything gets put together and executed based on the CLASSPATH at that time.
Java 在编译时实际上并不链接任何东西。它仅使用在 CLASSPATH 中找到的匹配类来验证语法。直到运行时,所有东西都被放在一起并基于当时的 CLASSPATH 执行。
回答by BalusC
Compiletime dependencies are only the dependencies (other classes) which you use directlyin the class you're compiling. Runtime dependencies covers both the direct and indirect dependencies of the class you're running. Thus, runtime dependencies includes dependencies of dependencies and any reflection dependencies like classnames which you have in a String
, but are used in Class#forName()
.
编译时依赖项只是您在正在编译的类中直接使用的依赖项(其他类)。运行时依赖项涵盖您正在运行的类的直接和间接依赖项。因此,运行时依赖项包括依赖项的依赖项和任何反射依赖项,例如您在 a 中拥有String
但在Class#forName()
.
回答by Martin Algesten
An easy example is to look at an api like the servlet api. To make your servlets compile, you need the servlet-api.jar, but at runtime the servlet container provides a servlet api implementation so you do not need to add servlet-api.jar to your runtime class path.
一个简单的例子是查看像 servlet api 这样的 api。要编译您的 servlet,您需要 servlet-api.jar,但在运行时 servlet 容器提供了一个 servlet api 实现,因此您不需要将 servlet-api.jar 添加到您的运行时类路径中。
回答by gpeche
Compile-time dependency: You need the dependency in your
CLASSPATH
to compile your artifact. They are produced because you have some kind of "reference" to the dependency hardcoded in your code, such as callingnew
for some class, extending or implementing something (either directly or indirectly), or a method call using the directreference.method()
notation.Run-time dependency: You need the dependency in your
CLASSPATH
to run your artifact. They are produced because you execute code that accesses the dependency (either in a hardcoded way or via reflection or whatever).
编译时依赖:你需要你的依赖
CLASSPATH
来编译你的工件。它们的产生是因为您对代码中硬编码的依赖项有某种“引用”,例如调用new
某个类、扩展或实现某些内容(直接或间接)或使用直接reference.method()
表示法的方法调用。运行时依赖:你需要依赖
CLASSPATH
来运行你的工件。它们的产生是因为您执行访问依赖项的代码(以硬编码方式或通过反射或其他方式)。
Although compile-time dependency usually implies run-time dependency, you can have a compile-time only dependency. This is based on the fact that Java only links class dependencies on first access to that class, so if you never access a particular class at run-time because a code path is never traversed, Java will ignore both the class and its dependencies.
尽管编译时依赖通常意味着运行时依赖,但您可以拥有仅编译时依赖。这是基于 Java 仅在第一次访问该类时链接类依赖项的事实,因此如果您在运行时从未访问特定类,因为从未遍历过代码路径,Java 将忽略该类及其依赖项。
Example of this
这个例子
In C.java (generates C.class):
在 C.java 中(生成 C.class):
package dependencies;
public class C { }
In A.java (generates A.class):
在 A.java(生成 A.class)中:
package dependencies;
public class A {
public static class B {
public String toString() {
C c = new C();
return c.toString();
}
}
public static void main(String[] args) {
if (args.length > 0) {
B b = new B();
System.out.println(b.toString());
}
}
}
In this case, A
has a compile-time dependency on C
through B
, but it will only have a run-time dependency on C if you pass some parameters when executing java dependencies.A
, as the JVM will only try to solve B
's dependency on C
when it gets to execute B b = new B()
. This feature allows you to provide at runtime only the dependencies of the classes that you use in your code paths, and ignore the dependencies of the rest of the classes in the artifact.
在这种情况下,A
对C
through有编译时依赖B
,但如果在执行时传递一些参数,它只会对 C 有运行时依赖java dependencies.A
,因为 JVM 只会尝试解决对它何时执行B
的依赖. 此功能允许您在运行时仅提供您在代码路径中使用的类的依赖项,而忽略工件中其余类的依赖项。C
B b = new B()
回答by stdout
For Java, compile time dependency is your source code's dependency. For instance, if class A calls a method from class B, then A is dependent to B at the compile time since A has to know about B (type of B) to be compiled. The trick here should be this: Compiled code is not a complete and executable code yet. It includes replaceable addresses (symbols, metadata) for the sources which are not yet compiled or existing in external jars. During linking, those addresses must be replaced by actual adresses in the memory. To do it properly, correct symbols/adresses should be created. And this can be done with the type of the class (B). I believe that's the main dependency at the compile time.
对于 Java,编译时依赖是源代码的依赖。例如,如果类 A 从类 B 调用一个方法,那么 A 在编译时依赖于 B,因为 A 必须知道要编译的 B(B 的类型)。这里的技巧应该是这样的:编译后的代码还不是完整的可执行代码。它包括尚未编译或存在于外部 jar 中的源的可替换地址(符号、元数据)。在链接期间,这些地址必须由内存中的实际地址替换。要正确执行此操作,应创建正确的符号/地址。这可以通过类 (B) 的类型来完成。我相信这是编译时的主要依赖项。
Runtime dependency is more related with the actual flow-of-control. It involes actual memory addresses. It's a dependency that you have when your program is running. You need class B details here like implementations, not only the type info. If the class not exists, then you will get RuntimeException and JVM will exit.
运行时依赖与实际的控制流更相关。它涉及实际的内存地址。这是程序运行时的依赖项。您在这里需要 B 类详细信息,例如实现,而不仅仅是类型信息。如果该类不存在,那么您将获得 RuntimeException 并且 JVM 将退出。
Both dependencies, generally and shouldn't, flow the same direction. This is a matter of OO design though.
这两个依赖项,通常并且不应该,流向相同的方向。不过,这是面向对象设计的问题。
In C++, compilation is a bit different (not just-in-time) but it has a linker too. So the process might be thought similar to Java I guess.
在 C++ 中,编译有点不同(不仅仅是及时),但它也有一个链接器。所以这个过程可能被认为类似于我猜的 Java。