You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorldApp/class
A common mistake made by beginner programmers is to try and run the java launcher on the .class file that was created by the compiler. For example, you'll get this error if you try to run your program with java HelloWorldApp.class instead of java HelloWorldApp. Remember, the argument is the name of the class that you want to use, not the filename.
즉, 바이트 코드를 실행시키기 위해서 파일 이름이 아니라 실행시키려는 클래스의 이름을 인수로 전달해야 합니다.
그렇다면 어떻게 클래스를 JVM에 적재할 수 있을까요?
JVM의 Classloader가 그 역할을 수행하고 있습니다. Classloader는 두 가지 방식의 클래스 로딩 방식을 지원 합니다.
로드타임 동적 로딩(Load-Time Dynamic Loading)
런타임 동적 로딩(Run-TIme Dynamic Loading)
( 클래스 로더의 구조)
1. 로드 타입 동적 로딩
클래스 로더가 로드할때 동적으로 클래스가 로딩되는 경우
java Calculator와 같이 명령어로 계산기 클래스를 실행하게 되면 로드타임 동적 로딩이 실행되는데
이때 Bootstrap ClassLoader가 실행되어 내부적으로 Object 클래스를 읽어 옵니다.(모든 클래스는 Object를 상속받기 때문에 먼저 불러오게 됩니다.)
이후 Calculator 클래스를 로딩하기 위해 해당 클래스의 바이트 코드를 읽어옵니다.
이때 내부적으로 사용되는 클래스들을 같이 로딩합니다. 만약 단순 Hello World 출력이라면 java.lang.String, java.lang.System과 같은 클래스들을 사용하므로 같이 로딩됩니다.
2. 런타임 동적 로딩
실제 런타임 환경에서 이루어지는 동적 클래스 로딩
런타임 동적 로딩은 대표적으로 String[] args 인자를 생각해볼 수 있습니다.
Class klass = Class.forName(args[0]); 다음과 같은 코드가 main()메소드에 포함되어 있다면 런타임 시점에서밖에 확인할 방법이 없습니다.
따라서 실제 main() 메소드가 실행되다가 해당 라인을 만나게 되는경우에 args[0]이 어떤 클래스 인자인지 파악할 수 있습니다.
참고
만약 .java가 붙은 텍스트 파일 이름과, 파일 내부에 선언된 클래스 명이 다르다면? 이건 컴파일 단계에서 부터 오류를 뱉습니다.
결국 .java 파일을 컴파일 하기 위해서는 내부에 선언된 클래스의 이름과 파일의 이름이 동일해야 합니다.
여러개의 클래스를 한 파일에서 선언한다면?
이때는 public이 붙은 클래스의 이름은 반드시 파일의 이름과 동일해야 합니다. 그렇지 않으면 다음과 같은 컴파일 에러가 발생합니다!
조사하면서 아쉬운점
클래스로더의 구조와 동작과정을 거의 겉핥기 수준으로 파악한 느낌이 강합니다 ㅎㅎ
좀 더 공부해야겠지만 아직은 많이 어려운 내용이라.. 일단 이정도 수준에서 마무리 하고 더 공부해서 보충해보겠습니다!
🤔 왜 이슈를 생성했나요?
터미널 환경에서 자바 코드를 컴파일하고 실행하는 과정에서 어떻게 JVM까지 바이트 코드가 전달될까? 궁금증이 생겨 조사해봤습니다!
😁 공유하고 싶은 내용:
java Calculator 명령어는 어떻게 바이트코드를 어떻게 JVM에 적재할까?
컴파일된 바이트 코드인 .class 파일을 확장자와 함께 실행하려고 하면 다음과 같은 예외가 발생합니다.
컴파일된 바이트 코드를 실행하기 위해서는 .class 확장자를 생략해야 하기 때문입니다.
Oracle docs에서는 위와 같은 오류에 대해 다음과 같이 설명하고 있습니다.
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorldApp/class
java
launcher on the.class
file that was created by the compiler. For example, you'll get this error if you try to run your program withjava HelloWorldApp.class
instead ofjava HelloWorldApp
. Remember, the argument is the name of the class that you want to use, not the filename.즉, 바이트 코드를 실행시키기 위해서 파일 이름이 아니라 실행시키려는 클래스의 이름을 인수로 전달해야 합니다.
그렇다면 어떻게 클래스를 JVM에 적재할 수 있을까요?
JVM의
Classloader
가 그 역할을 수행하고 있습니다. Classloader는 두 가지 방식의 클래스 로딩 방식을 지원 합니다.( 클래스 로더의 구조)
1. 로드 타입 동적 로딩
클래스 로더가 로드할때 동적으로 클래스가 로딩되는 경우
java Calculator
와 같이 명령어로 계산기 클래스를 실행하게 되면로드타임 동적 로딩
이 실행되는데이때 Bootstrap ClassLoader가 실행되어 내부적으로
Object
클래스를 읽어 옵니다.(모든 클래스는 Object를 상속받기 때문에 먼저 불러오게 됩니다.)이후 Calculator 클래스를 로딩하기 위해 해당 클래스의 바이트 코드를 읽어옵니다.
이때 내부적으로 사용되는 클래스들을 같이 로딩합니다. 만약 단순 Hello World 출력이라면 java.lang.String, java.lang.System과 같은 클래스들을 사용하므로 같이 로딩됩니다.
2. 런타임 동적 로딩
실제 런타임 환경에서 이루어지는 동적 클래스 로딩
런타임 동적 로딩은 대표적으로 String[] args 인자를 생각해볼 수 있습니다.
Class klass = Class.forName(args[0]);
다음과 같은 코드가 main()메소드에 포함되어 있다면 런타임 시점에서밖에 확인할 방법이 없습니다.따라서 실제 main() 메소드가 실행되다가 해당 라인을 만나게 되는경우에 args[0]이 어떤 클래스 인자인지 파악할 수 있습니다.
참고
조사하면서 아쉬운점
클래스로더의 구조와 동작과정을 거의 겉핥기 수준으로 파악한 느낌이 강합니다 ㅎㅎ
좀 더 공부해야겠지만 아직은 많이 어려운 내용이라.. 일단 이정도 수준에서 마무리 하고 더 공부해서 보충해보겠습니다!
📌 참고자료, 공유하고 싶은 자료
Fundamental of JVM and Class Loader in java - Java JVM과 Class Loader의 동작 과정 이해
The text was updated successfully, but these errors were encountered: