컴파일 시간과 런타임 종속성-Java


92

Java에서 컴파일 시간과 런타임 종속성의 차이점은 무엇입니까? 클래스 경로와 관련이 있지만 어떻게 다릅니 까?

답변:


79
  • 컴파일 시간 종속성 : CLASSPATH아티팩트를 컴파일 하려면에 종속성이 필요합니다 . new클래스 호출 , 무언가 확장 또는 구현 (직접 또는 간접), 직접 reference.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());
        }
    }
}

이 경우 AC통해 컴파일 시간 종속성이 B있지만 java dependencies.AJVM이 실행될 때 B의 종속성 을 해결하려고 시도하므로 실행할 때 일부 매개 변수를 전달하면 C에만 런타임 종속성이 있습니다. . 이 기능을 사용하면 코드 경로에서 사용하는 클래스의 종속성 만 런타임에 제공하고 아티팩트에있는 나머지 클래스의 종속성을 무시할 수 있습니다.CB b = new B()


1
나는 이것이 이제 매우 오래된 대답이라는 것을 알고 있지만 JVM이 처음부터 런타임 종속성으로 C를 어떻게 가질 수 없습니까? "여기에 C에 대한 참조가 있습니다. 종속성으로 추가 할 시간"을 인식 할 수 있다면 JVM이이를 인식하고 그것이 어디에 있는지 알고 있기 때문에 C는 본질적으로 종속성이 아닌가?
wearebob

@wearebob 내가 추측하는 방식으로 지정할 수 있었지만 지연 연결이 더 낫다고 결정했으며 개인적으로 위에 언급 된 이유에 동의합니다. 필요한 경우 일부 코드를 사용할 수 있지만 강제로 포함하지 않습니다. 필요하지 않은 경우 배포. 타사 코드를 다룰 때 매우 편리합니다.
gpeche 19-06-07

하지만 어딘가에 jar가 배포되어 있다면 이미 모든 종속성을 포함해야 할 것입니다. 인수를 사용하여 실행되는지 여부를 알지 못하므로 (그래서 C를 사용할지 여부를 알지 못하므로) 어느 쪽이든 C를 사용할 수 있어야합니다. 처음부터 클래스 경로에 C가 없어서 메모리 / 시간이 어떻게 절약되는지 알 수 없습니다.
wearebob

1
@wearebob JAR은 모든 종속성을 포함 할 필요가 없습니다. 그렇기 때문에 거의 모든 중요하지 않은 응용 프로그램에는 / lib 디렉토리 또는 여러 JAR이 포함 된 유사한 디렉토리가 있습니다.
gpeche

34

쉬운 예는 서블릿 API와 같은 API를 보는 것입니다. 서블릿을 컴파일하려면 servlet-api.jar가 필요하지만 런타임시 서블릿 컨테이너는 서블릿 API 구현을 제공하므로 런타임 클래스 경로에 servlet-api.jar을 추가 할 필요가 없습니다.


설명을 위해 (이것은 나를 혼란스럽게합니다), 만약 당신이 maven을 사용하고 전쟁을 구축한다면, "servlet-api"는 일반적으로 "런타임"의존성 대신 "제공된"의존성이며, 이것은 전쟁에 포함되게 할 것입니다. 나는 맞다.
xdhmoore

2
'제공됨'은 컴파일 시간에 포함하지만 WAR 또는 기타 종속성 컬렉션에 번들로 제공하지 않음을 의미합니다. 'runtime'은 그 반대입니다 (컴파일시 사용할 수 없지만 WAR과 함께 패키지 됨).
KC Baltz

30

컴파일러는 라이브러리에 대한 호출을 컴파일하기 위해 올바른 클래스 경로가 필요합니다 (컴파일 시간 종속성).

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 인 매개 변수를 취하는 클래스 인 메소드 foo(I1 i1)와 메소드 bar(L1 l1)가 있습니다. C1은 I1 및 L1에 대한 컴파일 시간 종속성을 갖습니다.

기본적으로 흥미로운 작업을 수행하려면 클래스가 클래스 경로의 다른 클래스 및 인터페이스와 인터페이스해야합니다. 해당 라이브러리 인터페이스 집합에 의해 형성된 클래스 / 인터페이스 그래프 는 컴파일 시간 종속성 체인을 생성합니다. 라이브러리 구현 은 런타임 종속성 체인을 생성합니다. 런타임 종속성 체인은 런타임 종속적이거나 실패 속도가 느립니다. L1 구현이 때때로 클래스 L2의 개체를 인스턴스화하는 데 의존하고 해당 클래스가 하나의 특정 시나리오에서만 인스턴스화되는 경우 다음을 제외하고 종속성이 없습니다. 그 시나리오.


1
예제 1의 컴파일 타임 종속성이 L1이어야하지 않습니까?
BalusC 2010

감사합니다. 클래스 로딩은 런타임에 어떻게 작동합니까? 컴파일 타임에는 이해하기 쉽습니다. 그러나 런타임에 버전이 다른 두 개의 Jar가있는 경우 어떻게 작동합니까? 어느 것을 선택합니까?
Kunal

1
기본 클래스 로더가 클래스 경로를 가져 와서 순서대로 단계를 수행한다고 확신합니다. 따라서 클래스 경로에 동일한 클래스 (예 : com.example.fooutils.Foo)를 포함하는 두 개의 jar가있는 경우 클래스 경로에서 첫 번째입니다. 그렇지 않으면 모호성을 나타내는 오류가 발생합니다. 그러나 클래스 로더에 대한 자세한 정보를 원하면 별도의 질문을해야합니다.
Jason S

첫 번째 경우에는 컴파일 시간 종속성이 L2에도 있어야한다고 생각합니다. 즉 문장은 다음과 같아야합니다. 1) 클래스 C1이 라이브러리 클래스 L1을 호출하고 L1이 라이브러리 클래스 L2를 호출하면 C1은 L1에 대한 런타임 종속성을 가지며 L2이지만 L1 및 L2에 대한 컴파일 시간 종속성 만 있습니다. 이것은 컴파일 타임에 자바 컴파일러가 L1을 확인할 때와 마찬가지로 L1이 참조하는 다른 모든 클래스도 확인합니다 (Class.forName ( "myclassname)과 같은 동적 종속성 제외). 그렇지 않으면 어떻게 확인합니까? 컴파일이 잘 작동합니다. 그렇지 않다고 생각한다면 설명해주세요
Rajesh Goel

1
아니요. Java에서 컴파일 및 연결이 어떻게 작동하는지 읽어야합니다. 컴파일러는 외부 클래스를 참조 할 때 해당 클래스 를 사용 하는 방법, 예를 들어 메서드와 필드가 무엇인지에 관심이 있습니다. 외부 클래스의 메서드에서 실제로 어떤 일이 발생하는지는 상관하지 않습니다. L1이 L2를 호출하면 L1의 구현 세부 사항이고 L1은 이미 다른 곳에서 컴파일되었습니다.
Jason S

13

Java는 실제로 컴파일 타임에 어떤 것도 링크하지 않습니다. CLASSPATH에서 찾은 일치하는 클래스를 사용하여 구문 만 확인합니다. 모든 것이 합쳐지고 그 당시 CLASSPATH를 기반으로 실행되는 것은 런타임까지입니다.


로드 시간까지 ... 런타임은로드 시간과 다릅니다.
overexchange

11

컴파일 시간 종속성은 컴파일하는 클래스에서 직접 사용하는 종속성 (다른 클래스) 일뿐 입니다. 런타임 종속성은 실행중인 클래스의 직접 및 간접 종속성을 모두 포함합니다. 따라서 런타임 종속성에는 종속성의 종속성과 .NET에서 사용되는 클래스 이름과 같은 리플렉션 종속성 String이 포함됩니다 Class#forName().


감사합니다. 클래스 로딩은 런타임에 어떻게 작동합니까? 컴파일 타임에는 이해하기 쉽습니다. 그러나 런타임에 버전이 다른 두 개의 Jar가있는 경우 어떻게 작동합니까? 클래스 경로에 다른 클래스의 여러 클래스가있는 경우 Class.forName ()은 어떤 클래스를 선택합니까?
Kunal 2011

물론 이름과 일치하는 것. 이 경우 실제로 "같은 클래스의 여러 버전을"의미, 그것은 클래스 로더에 따라 달라집니다. "가장 가까운"것이로드됩니다.
BalusC 2010

글쎄, 나는 당신이 A.jar와 함께 A, B.jar과 함께 B extends A그리고 C.jar와 함께 C extends B있다면 C.jar는 A에 대한 C 종속성이 간접적이지만 A.jar의 컴파일 시간에 의존한다고 생각합니다.
gpeche 2010

1
모든 컴파일 시간 종속성의 문제는 인터페이스 종속성입니다 (인터페이스가 클래스의 메서드를 통하든, 인터페이스의 메서드를 통하든, 또는 클래스 또는 인터페이스 인 인수를 포함하는 메서드를 통하든)
Jason S

2

Java의 경우 컴파일 시간 종속성은 소스 코드의 종속성입니다. 예를 들어, 클래스 A가 클래스 B의 메서드를 호출하면 A가 컴파일 할 B (B 유형)에 대해 알아야하므로 컴파일 시간에 A가 B에 종속됩니다. 여기서 트릭은 다음과 같아야합니다. 컴파일 된 코드는 아직 완전하고 실행 가능한 코드가 아닙니다. 아직 컴파일되지 않았거나 외부 jar에 존재하지 않는 소스에 대한 교체 가능한 주소 (기호, 메타 데이터)가 포함됩니다. 연결 중에 이러한 주소는 메모리의 실제 주소로 대체되어야합니다. 제대로하려면 올바른 기호 / 주소를 만들어야합니다. 그리고 이것은 클래스 (B)의 유형으로 할 수 있습니다. 컴파일 타임에 이것이 주요 의존성이라고 생각합니다.

런타임 종속성은 실제 제어 흐름과 더 관련이 있습니다. 실제 메모리 주소를 포함합니다. 프로그램이 실행 중일 때 갖는 종속성입니다. 여기에는 유형 정보뿐만 아니라 구현과 같은 클래스 B 세부 정보가 필요합니다. 클래스가 없으면 RuntimeException이 발생하고 JVM이 종료됩니다.

일반적으로 그리고해서는 안되는 두 종속성은 동일한 방향으로 흐릅니다. 이것은 OO 디자인의 문제입니다.

C ++에서 컴파일은 (Just-In-Time이 아니라) 약간 다르지만 링커도 있습니다. 따라서 프로세스는 내가 생각하는 Java와 유사하다고 생각할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.