0

Java에서 클래스를 처음 액세스 할 때 (새 인스턴스 만들기, 정적 메서드 또는 정적 필드 호출) 알지만이 간단한 예제에서는 런타임에 내 ClassPath에없는 일부 클래스를 사용하는 jar 파일을 실행하십시오. 첫 번째 액세스에서 클래스를로드하기 때문에 예외가 발생하기 전에 정적 블록 및 main 메서드에서 내 메시지를 인쇄 할 것으로 예상됩니다. 하지만 "스레드에서 예외"메인 "java.lang.NoClassDefFoundError : com/example/DateAbstract"있어 아무 것도 인쇄되지 않습니다. 추상 클래스 또는 기본 클래스의 인터페이스를 사용하여 해당 클래스 또는 인터페이스가 다른 jar 파일에있는 경우에 발생했습니다. 내 또 다른 항아리에NoClassDefFoundError 런타임시 Class 클래스에 클래스를 추가 할 때 기본 클래스에서 abstract 나 인터페이스를 사용할 때

public class Driver { 
static { System.out.println("I am first.[static block]"); } 
public static void main(String[] args) { 
    System.out.println("I am first.[ main method]"); 
    DateAbstract date = new CustomDate(); 
    System.out.println(date.sayDate()); 
} 

:

public class CustomDate extends DateAbstract { 
@Override 
public String sayDate() { 
    return new Date().toString(); 
} 
public abstract class DateAbstract { 
public abstract String sayDate(); 

} 

내가 런타임에 클래스 패스 내 클래스를 추가하기위한이 코드를 사용

. 아무것도 바뀌지 않았다. 정적 블록을 실행하기 전에 실행을 중지했습니다.

public class Driver { 
static { 
    System.out.println("I am first.[static block]"); 
    try { 
     URL url = new File("lib/DateApi.jar").toURI().toURL(); 
     URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader(); 
     Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); 
     method.setAccessible(true); 
     method.invoke(urlClassLoader,url); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 
public static void main(String[] args) { 
    System.out.println("I am first.[ main method]"); 
    DateAbstract date = new CustomDate(); 
    System.out.println(date.sayDate()); 
} 

} 

질문 : 왜 이런 일이 일어나고 어떻게 해결할 수 있습니까?

답변

0

Java 클래스에서 첫 번째 액세스시로드된다는 것은 올바르지 않습니다. 이것을 초기화 클래스와 혼동하고 있습니다. 이는 static 이니셜 라이저 블록 및 필드 초기화 프로그램의 Java 코드를 실행하는 것을 의미합니다. 로드 및 검증은 이전 시점에 일어날 수 있습니다. 이 스펙은 JVM에 대해 약간의 자유를 제공한다. 여기

중요한 점은 main 방법은 컴파일시의 형태 DateAbstract의 변수에 입력 CustomDate의 객체, 상점을 인스턴스화하고 해당 변수에 sayDate()를 호출하려고 할 것입니다. CustomDate을 인스턴스화하고 DateAbstract.sayDate()을 호출하는이 조합의 정확성 즉, CustomDate이 하위 유형 DateAbstract인지 여부를 확인해야합니다. 따라서이 두 클래스의로드는 이미 확인 시간에서 발생합니다.

쉽게 원인을 확인할 수 있습니다. 지역 변수 date의 유형을 CustomDate으로 변경하면 메소드 호출의 인스턴스화 된 유형과 수신자 유형이 동일하므로 유형을로드하지 않고도 정확성을 입증 할 수 있으므로 실제 시도가 지연됩니다. CustomDate을 인스턴스화합니다. 따라서 메시지가 인쇄됩니다.

여전히 로딩 시간은 구현에 특정한 세부 사항입니다. 다른 JVM은 검증을 위해 필요하지 않더라도 참조 된 클래스를 열심히로드 할 수 있습니다. 지연로드를 보장하는 유일한 방법은 동적로드를 사용하는 것입니다 (예 : Class.forName(String). 이런 방식으로 분리 된 클래스 내에서는 모든 타입이 다시 일반적으로 참조 될 수 있습니다. 따라서 클래스 경로를 조정 한 후에 동적로드를 한 번 수행하면 코드 작성 방법이나 성능에 큰 영향을 미치지 않습니다. 물론 동일한 클래스 내에서 클래스 경로와 코드에 따라 코드를 조정하면 안정적으로 작동하지 않습니다.