3. JDK에 포함된 JRE를 통해 프로그램 실행하기
1. Java 프로그램 실행하기
자바 언어로 작성된 .java 확장자를 가진 파일을 실행하기 위한 단계는 다음과 같음
Step 1, 소스 코드
인간이 쉽게 이해하고 작성할 수 있는 자연어
컴파일러를 통해 컴파일 과정을 거쳐 바이트 코드로 변환됨
System.out.println();Step 2, 바이트 코드
소프트웨어(JVM)가 이해할 수 있는 반 기계어(half)
0: getstatic..Step 3, 기계어
하드웨어(CPU core)가 이해할 수 있는 완전한 형태의 기계어
0101011..2. 세부 실행 단계
1번에서 설명된 Java 프로그램의 세부 실행 단계는 다음과 같음
2-1. 작성한 소스 코드를 컴파일하기
컴파일이란 자바 언어로 작성된 소스 코드를 바이트 코드로 변환하는 과정
→ 변환된 바이트 코드는 자바 가상 머신인 JVM이 이해하고 실행할 수 있는 코드로 활용됨
이러한 컴파일은 자바 컴파일러인 javac.exe를 통해 수행할 수 있음
javac 명령어
.java 파일을 JVM이 실행할 수 있는 .class 파일로 변환을 수행하는 명령어
→ javac.exe 파일을 통해 동작함
Hello.java 파일 컴파일하기
javac Hello.java // 자바씨~ 컴파일 해줘정리하면, 자바 언어로 작성된 하나의 프로그램을 실행하기 위해서는 먼저 컴파일 과정을 거쳐야 함
2-2. 컴파일된 바이트 코드 확인하기
컴파일된 바이트 코드는 바이너리 형태이기 때문에 일반 텍스트 에디터나 메모장을 통해 확인이 어려움
간단한 Linux/MacOS 명령어를 통해 확인
xxd Hello.class # xxd: .class 파일을 Hex(16진수) 형태로 출력
# 실행 결과
00000000: cafe babe 0000 003d 001d 0a00 0200 0307 .......=........
00000010: 0004 0c00 0500 0601 0010 6a61 7661 2f6c ..........java/l
00000020: 616e 672f 4f62 6a65 6374 0100 063c 696e ang/Object...<in
00000030: 6974 3e01 0003 2829 5609 0008 0009 0700 it>...()V.......
00000040: 0a0c 000b 000c 0100 106a 6176 612f 6c61 .........java/la
00000050: 6e67 2f53 7973 7465 6d01 0003 6f75 7401 ng/System...out.
00000060: 0015 4c6a 6176 612f 696f 2f50 7269 6e74 ..Ljava/io/Print
00000070: 5374 7265 616d 3b08 000e 0100 0b48 656c Stream;......Hel
00000080: 6c6f 2057 6f72 6c64 0a00 1000 1107 0012 lo World........
00000090: 0c00 1300 1401 0013 6a61 7661 2f69 6f2f ........java/io/
000000a0: 5072 696e 7453 7472 6561 6d01 0007 7072 PrintStream...pr
000000b0: 696e 746c 6e01 0015 284c 6a61 7661 2f6c intln...(Ljava/l
000000c0: 616e 672f 5374 7269 6e67 3b29 5607 0016 ang/String;)V...
000000d0: 0100 0548 656c 6c6f 0100 0443 6f64 6501 ...Hello...Code.
000000e0: 000f 4c69 6e65 4e75 6d62 6572 5461 626c ..LineNumberTabl
000000f0: 6501 0004 6d61 696e 0100 1628 5b4c 6a61 e...main...([Lja
00000100: 7661 2f6c 616e 672f 5374 7269 6e67 3b29 va/lang/String;)
00000110: 5601 000a 536f 7572 6365 4669 6c65 0100 V...SourceFile..
00000120: 0a48 656c 6c6f 2e6a 6176 6100 2100 1500 .Hello.java.!...
00000130: 0200 0000 0000 0200 0100 0500 0600 0100 ................
00000140: 1700 0000 1d00 0100 0100 0000 052a b700 .............*..
00000150: 01b1 0000 0001 0018 0000 0006 0001 0000 ................
00000160: 0001 0009 0019 001a 0001 0017 0000 0025 ...............%
00000170: 0002 0001 0000 0009 b200 0712 0db6 000f ................
00000180: b100 0000 0100 1800 0000 0a00 0200 0000 ................
00000190: 0300 0800 0400 0100 1b00 0000 0200 1c ...............2-3. 바이트 코드를 이해할 수 있는 형태로 변환하기
컴파일된 결과인 바이트 코드를 다시 인간이 이해할 수 있는 형태로 복원하기 위해서는 디컴파일(Decompile) 과정을 거쳐야 함
하지만 자바는 별도의 디컴파일까지 거치지 않고도,
바이트 코드로 작성된 .class 파일의 내부 구조를 간단하게 분석할 수 있도록 기능도 제공함
javap.exe를 통해 활용 가능
javap -c Hello # Hello.class 해독
# 실행 결과
Compiled from "Hello.java"
public class Hello {
public Hello(); # Hello() 생성자를 통해 Hello 객체 생성
Code:
0: aload_0 # 지역 변수 0(this 객체)를 스택에 로드
1: invokespecial #1 // Method java/lang/Object."<init>":()V, Object() 호출
4: return # 생성자 호출 종료
# -> 기본 생성자를 호출할 때, super()가 호출됨
public static void main(java.lang.String[]);
Code:
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
# System.out 객체인 PrintStream을 가져옴
3: ldc #13 // String Hello World
# 문자열 "Hello World"를 문자열 상수 풀(String Constant Pool)에서 로드
5: invokevirtual #15 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
# Printstream.println() 메서드 호출
8: return # 메서드 종료
# -> main() 내부에서 System.out.println("Hello World")를 수행하는 과정
}javac가 컴파일을 수행하는 과정에서 참조하는 클래스 패스 확인하기
javac -verbose Hello.java실행 결과
[search path for class files: C:\Users\82107\Desktop\install\jdk-17.0.8+7\lib\modules,.]
[loading /modules/java.base/java/lang/Object.class]
[loading /modules/java.base/java/lang/String.class]
[loading /modules/java.base/java/lang/Deprecated.class]
[loading /modules/java.base/java/lang/annotation/Retention.class]
[loading /modules/java.base/java/lang/annotation/RetentionPolicy.class]
[loading /modules/java.base/java/lang/annotation/Target.class]
[loading /modules/java.base/java/lang/annotation/ElementType.class]
[checking Hello]
[loading /modules/java.base/java/io/Serializable.class]
[loading /modules/java.base/java/lang/AutoCloseable.class]
[loading /modules/java.base/java/lang/System.class]
[loading /modules/java.base/java/io/PrintStream.class]
[loading /modules/java.base/java/lang/Appendable.class]
[loading /modules/java.base/java/io/Closeable.class]
[loading /modules/java.base/java/io/FilterOutputStream.class]
[loading /modules/java.base/java/io/OutputStream.class]
[loading /modules/java.base/java/io/Flushable.class]
[loading /modules/java.base/java/lang/Comparable.class]
[loading /modules/java.base/java/lang/CharSequence.class]
[loading /modules/java.base/java/lang/constant/Constable.class]
[loading /modules/java.base/java/lang/constant/ConstantDesc.class]
[wrote Hello.class]2-4. 컴파일된 바이트 코드 실행하기(Run)
앞서 간단하게 확인해본 바이트 코드는 java.exe를 통해 실행할 수 있음
00000000: cafe babe 0000 003d 001d 0a00 0200 0307 .......=........
00000010: 0004 0c00 0500 0601 0010 6a61 7661 2f6c ..........java/l
00000020: 616e 672f 4f62 6a65 6374 0100 063c 696e ang/Object...<in
00000030: 6974 3e01 0003 2829 5609 0008 0009 0700 it>...()V.......
00000040: 0a0c 000b 000c 0100 106a 6176 612f 6c61 .........java/la
00000050: 6e67 2f53 7973 7465 6d01 0003 6f75 7401 ng/System...out.Hello.class 파일 실행하기
java Hello # java 명령어 실행 시 .class는 생략하고 실행
# 실행 결과
"Hello World"Q. 왜 Hello.class가 아닌 Hello?
설명 보기
왜 Hello.class가 아닌 Hello?
JVM은 클래스를 실행할 때, .class 파일이 아닌 클래스 이름을 기준으로 찾음
→ Hello.class가 아니라 Hello라고 입력해야 JVM이 자동으로 .class 를 찾아서 로딩함
또한 JVM은 기본적으로 .(현재 디렉토리)를 포함하여 .class를 찾음
만약 java Hello.class로 실행할 경우,
JVM은 ‘Hello.class’라는 이름의 패키지나 클래스를 찾으려다 실패(ClassNotFoundException)