[java] NoClassDefFoundError와 ClassNotFoundException의 차이점은 무엇입니까?

차이점은 무엇이며 NoClassDefFoundError그리고 ClassNotFoundException?

무엇이 던져지게 하는가? 그들은 어떻게 해결할 수 있습니까?

새로운 jar 파일을 포함하도록 기존 코드를 수정할 때 종종 이러한 Throwable이 발생합니다. 웹 시작을 통해 배포 된 Java 응용 프로그램의 클라이언트 측과 서버 측 모두에서 적중했습니다.

내가 만난 이유 :

  1. build.xml코드의 클라이언트 측에 포함되지 않은 패키지
  2. 우리가 사용하는 새로운 jar에 대한 런타임 클래스 경로가 없습니다.
  3. 이전 jar과 버전 충돌

내가 오늘 이것들을 만날 때 나는 일을 잘하기 위해 흔적과 실수를한다. 더 명확하고 이해가 필요합니다.



답변

Java API 사양과의 차이점은 다음과 같습니다.

의 경우 ClassNotFoundException:

애플리케이션이 다음을 사용하여 문자열 이름을 통해 클래스에로드하려고 할 때 발생합니다.

  • forName클래스 의 메소드 Class.
  • findSystemClass클래스 의 메소드 ClassLoader.
  • loadClass클래스 의 메소드 ClassLoader.

지정된 이름의 클래스에 대한 정의를 찾을 수 없습니다.

의 경우 NoClassDefFoundError:

Java Virtual Machine 또는 ClassLoader인스턴스가 클래스의 정의 (일반 메소드 호출의 일부 또는 새 표현식을 사용하여 새 인스턴스를 작성하는 일부)를로드하려고 시도하고 클래스 정의를 찾을 수없는 경우 발생합니다.

검색된 클래스 정의는 현재 실행중인 클래스가 컴파일 될 때 존재하지만 정의를 더 이상 찾을 수 없습니다.

따라서 NoClassDefFoundError소스가 성공적으로 컴파일 될 때 발생하지만 런타임에 필요한 class파일을 찾을 수없는 것으로 보입니다 . 이것은 필요한 class파일이 모두 포함되어 있지 않은 JAR 파일의 배포 또는 프로덕션에서 발생할 수있는 것일 수 있습니다 .

에 관해서 ClassNotFoundException는 런타임에 클래스에 대한 반사 호출을 시도한 것일 수 있지만 프로그램이 호출하려는 클래스가 존재하지 않습니다.

둘 사이의 차이점은 하나는 Error이고 다른 하나는이라는 것입니다 Exception. with NoClassDefFoundErrorError및 Java Virtual Machine에서 찾은 클래스를 찾는 데 문제가 있습니다. 컴파일 타임에 작동 할 것으로 예상 된 프로그램은 class파일을 찾을 수 없어서 실행할 수 없거나 컴파일 타임 에 생성되거나 발생 된 것과 동일하지 않습니다. JVM이 프로그램을 시작할 수 없기 때문에 이것은 매우 중요한 오류입니다.

반면에는 ClassNotFoundExceptionException이므로 어느 정도 예상되며 복구 할 수있는 것입니다. 리플렉션을 사용하면 오류가 발생하기 쉬울 수 있습니다 (일부 예상대로 진행되지 않을 것으로 예상됩니다. 필요한 모든 클래스가 존재하는지 확인하는 컴파일 타임 검사가 없으므로 원하는 클래스를 찾는 데 문제가 런타임에 나타납니다. .


답변

보고 된 클래스를 ClassLoader에서 찾을 수없는 경우 ClassNotFoundException이 발생합니다. 이것은 일반적으로 클래스가 CLASSPATH에서 누락되었음을 의미합니다. 또한 문제의 클래스가 상위 클래스 로더에로드 된 다른 클래스에서로드하려고하므로 하위 클래스 로더의 클래스가 표시되지 않을 수도 있습니다. App Server와 같이보다 복잡한 환경에서 작업하는 경우가 종종 있습니다 (WebSphere는 이러한 클래스 로더 문제로 유명합니다).

사람들은 종종 혼동하는 경향 java.lang.NoClassDefFoundErrorjava.lang.ClassNotFoundException중요한 차이있다 그러나. 예를 들어 예외 (실제로 오류 java.lang.NoClassDefFoundError는 java.lang.Error의 서브 클래스입니다)

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

ActiveMQConnectionFactory 클래스가 CLASSPATH에 없다는 것을 의미하지는 않습니다. 사실 그 반대입니다. 이는 클래스 로더가 ActiveMQConnectionFactory 클래스를 찾았지만 클래스를로드하려고 할 때 클래스 정의를 읽는 중에 오류가 발생했음을 의미합니다. 일반적으로 문제의 클래스에 클래스 로더에서 찾을 수없는 클래스를 사용하는 정적 블록 또는 멤버가있는 경우 발생합니다. 따라서 범인을 찾으려면 해당 클래스의 소스 (이 경우 ActiveMQConnectionFactory)를보고 정적 블록 또는 정적 멤버를 사용하는 코드를 찾으십시오. 소스에 액세스 할 수 없으면 JAD를 사용하여 간단히 디 컴파일하십시오.

코드를 검사 할 때 아래와 같은 코드 행을 찾으면 CLASSPATH에 SomeClass 클래스가 있는지 확인하십시오.

private static SomeClass foo = new SomeClass();

팁 : 클래스가 속한 jar을 찾으려면 웹 사이트 jarFinder를 사용할 수 있습니다. 이를 통해 와일드 카드를 사용하여 클래스 이름을 지정하고 jar 데이터베이스에서 클래스를 검색 할 수 있습니다. jarhoo를 사용하면 동일한 작업을 수행 할 수 있지만 더 이상 사용할 수 없습니다.

클래스가 속한 jar을 로컬 경로에서 찾으려면 jarscan ( http://www.inetfeedback.com/jarscan/ ) 과 같은 유틸리티를 사용할 수 있습니다 . 단지 찾으려는 클래스와 jar 및 zip 파일에서 클래스 검색을 시작하려는 루트 디렉토리 경로 만 지정하면됩니다.


답변

NoClassDefFoundError기본적으로 연결 오류입니다. (정적으로 “new”로) 객체를 인스턴스화하려고 시도 할 때 발생하며 컴파일 중에는 찾을 수 없습니다.

ClassNotFoundException더 일반적이며 존재하지 않는 클래스를 사용하려고 할 때 런타임 예외입니다. 예를 들어 함수에 매개 변수가 인터페이스를 허용하고 누군가 해당 인터페이스를 구현하는 클래스를 전달하지만 해당 클래스에 액세스 할 수는 없습니다. loadClass()또는 사용과 같은 동적 클래스 로딩의 경우도 다룹니다 Class.forName().


답변

NCDFE (NoClassDefFoundError)는 코드에서 “new Y ()”를 실행하고 Y 클래스를 찾을 수 없을 때 발생합니다.

다른 의견에서 알 수 있듯이 Y가 클래스 로더에서 누락되었을 수 있지만 Y 클래스가 서명되지 않았거나 서명이 잘못되었거나 코드에 표시되지 않는 다른 클래스 로더에 의해 Y가로드되었을 수 있습니다. 또는 Y가 Z에 의존하여 위의 이유로로드 할 수 없습니다.

이 경우 JVM은 X (NCDFE)로드 결과를 기억하며 Y를 요청할 때마다 이유를 알리지 않고 새 NCDFE를 던집니다.

클래스 {
  정적 클래스 b {}
  공개 정적 무효 메인 (문자열 인수 []) {
    System.out.println ( "첫 번째 시도 새 b () :");
    {new b ();를 시도하십시오 } catch (Throwable t) {t.printStackTrace ();}
    System.out.println ( "\ n 둘째 새 b () :") 시도;
    {new b ();를 시도하십시오 } catch (Throwable t) {t.printStackTrace ();}
  }
}

이것을 어딘가에 a.java로 저장하십시오.

이 코드는 단순히 새로운 “b”클래스를 두 번 인스턴스화하려고 시도합니다. 그 외에는 버그가 없으며 아무 것도하지 않습니다.

로 코드를 컴파일 한 javac a.java다음 호출하여 a를 실행하십시오. java -cp . a두 줄의 텍스트를 인쇄하면 오류없이 정상적으로 실행됩니다.

그런 다음 “a $ b.class”파일을 삭제하거나 가비지로 채우거나 a.class를 복사하여 누락되거나 손상된 클래스를 시뮬레이션하십시오. 다음과 같은 일이 발생합니다.

먼저 새로운 b ()를 시도하십시오.
java.lang.NoClassDefFoundError : a $ b
    a.main (a.java:5)에서
원인 : java.lang.ClassNotFoundException : a $ b
    java.net.URLClassLoader에서 $ 1.run (URLClassLoader.java:200)
    java.security.AccessController.doPrivileged (네이티브 메소드)
    java.net.URLClassLoader.findClass (URLClassLoader.java:188)에서
    java.lang.ClassLoader.loadClass (ClassLoader.java:307)에서
    sun.misc.Launcher $ AppClassLoader.loadClass (Launcher.java:301)에서
    java.lang.ClassLoader.loadClass (ClassLoader.java:252)에서
    java.lang.ClassLoader.loadClassInternal (ClassLoader.java:320)에서
    ... 1 더

두 번째 시도 새로운 b () :
java.lang.NoClassDefFoundError : a $ b
    a.main (a.java:7)에서

첫 번째 호출은 ClassNotFoundException (클래스를 찾을 수 없을 때 클래스 로더에 의해 발생)을 초래하며, 문제의 코드 ( new b())가 작동 하기 때문에 검사되지 않은 NoClassDefFoundError로 랩핑 되어야합니다.

두 번째 시도는 물론 실패하지만, 클래스 로더가 실패한 클래스 로더를 기억하는 것처럼 보이기 때문에 랩 된 예외는 더 이상 볼 수 없습니다. 당신은 실제로 일어난 일에 대한 단서가없는 NCDFE 만 봅니다.

따라서 근본 원인이없는 NCDFE가 표시되는 경우 오류가 발생한 원인을 찾기 위해 클래스가 처음로드 된 시점까지 추적 할 수 있는지 확인해야합니다.


답변

에서 http://www.javaroots.com/2013/02/classnotfoundexception-vs.html :

ClassNotFoundException: 클래스 로더가 클래스 경로에서 필요한 클래스를 찾을 수 없을 때 발생합니다. 따라서 기본적으로 클래스 경로를 확인하고 클래스 경로에 클래스를 추가해야합니다.

NoClassDefFoundError: 디버그하기가 더 어렵고 이유를 찾기가 어렵습니다. 컴파일 타임에 필요한 클래스가있을 때 발생하지만 런타임에 클래스가 변경되거나 제거되거나 클래스의 정적 초기화에서 예외가 발생했습니다. 로드중인 클래스가 클래스 경로에 있지만이 클래스에 필요한 클래스 중 하나가 제거되었거나 컴파일러에서로드하지 못했음을 의미합니다. 따라서이 클래스에 종속 된 클래스를 볼 수 있습니다.

:

public class Test1
{
}


public class Test
{
   public static void main(String[] args)
   {
        Test1 = new Test1();
   }

}

이제 두 클래스를 컴파일 한 후 Test1.class 파일을 삭제하고 Test 클래스를 실행하면 던져집니다.

Exception in thread "main" java.lang.NoClassDefFoundError: Test
    at Test1.main(Test1.java:5)
Caused by: java.lang.ClassNotFoundException: Test
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 1 more

ClassNotFoundException: 애플리케이션이 이름을 통해 클래스에로드하려고 시도하지만 지정된 이름을 가진 클래스에 대한 정의를 찾을 수 없습니다.

NoClassDefFoundError: JVM (Java Virtual Machine)이 클래스 정의를로드하려고 시도하고 클래스 정의를 찾을 수없는 경우 발생합니다.


답변

그들 각각을 얻는 이유와 그러한 오류를 다루는 방법에 대한 생각 과정은 무엇입니까?

그들은 밀접한 관련이 있습니다. ClassNotFoundExceptionJava가 이름으로 특정 클래스를 찾다가 성공적으로로드하지 못한 경우 A 가 발생합니다. A는 NoClassDefFoundError자바 일부 기존 코드에 링크 된 클래스를 찾고 갔을 때 발생합니다,하지만 하나의 이유 또는 다른 (예를 들어, 잘못된 클래스 경로, 자바, 라이브러리의 잘못된 버전의 잘못된 버전)을 위해 그것을 찾을 수 없습니다 철저 치명적이다 무언가 잘못되었다는 것을 나타냅니다.

C 배경이 있다면 CNFE는 dlopen()/에 대한 실패 dlsym()와 같으며 NCDFE는 링커의 문제입니다. 두 번째 경우, 관련 클래스 파일은 실제로 사용하려는 구성에서 컴파일되지 않아야합니다.


답변

예 # 1 :

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}

경우 com/example/Class1클래스 경로의 존재하지 않는, 다음이 발생합니다 ClassNotFoundException.

예 # 2 :

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}

경우 com/example/Class2B를 컴파일하는 동안 존재하지만, 실행하는 동안 발견되지, 다음이 발생합니다 NoClassDefFoundError.

둘 다 런타임 예외입니다.