编译时与运行时依赖关系 - Java

2022-08-31 09:01:45

Java 中的编译时和运行时依赖关系之间有什么区别?它与类路径有关,但它们有何不同?


答案 1
  • 编译时依赖项:需要中的依赖项来编译工件。之所以生成它们,是因为您对代码中硬编码的依赖项有某种“引用”,例如调用某个类,扩展或实现某些内容(直接或间接),或者使用直接表示法的方法调用。CLASSPATHnewreference.method()

  • 运行时依赖项:需要中的依赖项才能运行项目。生成它们是因为您执行访问依赖项的代码(以硬编码方式或通过反射或其他方式)。CLASSPATH

尽管编译时依赖关系通常意味着运行时依赖关系,但您可以具有仅编译时依赖关系。这是基于这样一个事实,即 Java 仅在首次访问时将类依赖关系链接到该类,因此,如果您由于从未遍历代码路径而在运行时访问特定类,则 Java 将忽略该类及其依赖项。

示例

在 C.java(生成 C.class):

package dependencies;
public class C { }

在 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());
        }
    }
}

在这种情况下,对 through 有一个编译时依赖性,但是如果你在执行时传递一些参数,它只会对 C 有运行时依赖性,因为 JVM 只会尝试解决 它对何时执行的依赖性。此功能允许您在运行时仅提供在代码路径中使用的类的依赖项,而忽略项目中其余类的依赖项。ACBjava dependencies.ABCB b = new B()


答案 2

编译器需要正确的类路径才能编译对库的调用(编译时依赖关系)

JVM 需要正确的类路径才能加载您正在调用的库中的类(运行时依赖项)。

它们可能在以下几个方面有所不同:

1) 如果类 C1 调用库类 L1,L1 调用库类 L2,则 C1 对 L1 和 L2 具有运行时依赖性,但对 L1 只有编译时依赖性。

2) 如果您的类 C1 使用 Class.forName() 或其他某种机制动态实例化接口 I1,并且接口 I1 的实现类是类 L1,则 C1 对 I1 和 L1 具有运行时依赖性,但仅对 I1 具有编译时依赖性。

编译时和运行时相同的其他“间接”依赖项:

3) 您的类 C1 扩展了库类 L1,L1 实现了接口 I1 并扩展了库类 L2:C1 在编译时依赖于 L1、L2 和 I1。

4)你的类C1有一个方法和一个方法,其中I1是一个接口,L1是一个接受接口I1参数的类:C1具有编译时依赖I1和L1。foo(I1 i1)bar(L1 l1)

基本上,要执行任何有趣的操作,您的类需要与类路径中的其他类和接口进行交互。由这组库接口形成的类/接口图产生编译时依赖关系链。库实现产生运行时依赖关系链。请注意,运行时依赖关系链依赖于运行时或失败缓慢:如果 L1 的实现有时依赖于实例化类 L2 的对象,并且该类仅在一个特定方案中实例化,则除了该方案之外,没有其他依赖关系。


推荐