자바 클래스 파일
1. 개요
자바 클래스 파일은 자바 가상 머신(JVM)에서 실행될 수 있는 바이트코드를 포함하는 이진 파일 형식이다. 2006년 JSR 202에 따라 클래스 파일 형식이 수정되었다. 클래스 파일은 매직 넘버(0xCAFEBABE), 클래스 파일 형식 버전, 상수 풀, 접근 플래그, 현재 클래스, 슈퍼 클래스, 인터페이스, 필드, 메서드, 속성 등 10가지 항목으로 구성된다. 클래스 파일은 가변 크기 항목을 포함하며, 파일 내 오프셋을 명시적으로 포함하지 않고, 파일의 처음부터 끝까지 순차적으로 분석된다.
| 파일 확장자 | .class |
|---|---|
| 유형 | 바이트코드 |
| 개발자 | 썬 마이크로시스템즈 |
| 설명 | 자바 가상 머신에서 실행할 수 있는 자바 바이트코드를 포함하는 파일 포맷이다. |
|---|---|
| 관련 파일 | .java (자바 소스 파일) |
| 사용 | 자바 클래스 애플릿 |
| 매직 넘버 | 0xCAFEBABE |
| 컨테이너 | JAR 파일 |
-
자바 플랫폼 -
블루레이
블루레이 디스크는 DVD 후속 매체로, 청색 레이저를 사용하여 고화질 영상과 음향을 제공하며 HD DVD와의 경쟁 후 고밀도 광디스크 표준으로 자리 잡았으나 스트리밍 서비스 성장으로 녹화용 디스크 생산이 중단되는 추세이다. -
자바 플랫폼 -
자바 플랫폼, 마이크로 에디션
자바 ME는 임베디드 및 모바일 장치에서 자바 앱을 실행하는 플랫폼으로, 피처폰에서 주로 사용되었으며 다양한 프로파일과 에뮬레이터, 개발 도구를 제공하고 JSR을 통해 기능이 확장된다. -
파일 포맷 -
바로 가기
바로 가기는 운영체제에서 파일, 폴더, 프로그램, 웹 페이지에 대한 참조를 제공하는 기능 및 파일로, 사용자들이 원본에 빠르게 접근하도록 GUI 환경의 사용성을 향상시킨다. -
파일 포맷 -
EXE
EXE 파일 형식은 운영 체제에 따라 다양한 종류가 있는 실행 파일의 한 형태로, DOS MZ 실행 파일에서 PE, PE32+까지 발전해 왔으며, 코드, 데이터, 스택을 별도 관리하고 재배치 항목을 통해 실행 환경에 유연하게 대응하는 특징을 가진다.
2. 역사
자바 규격 요청 (JSR) 202에 따라 2006년 12월 11일에 클래스 파일 형식이 수정되었다. Java Specification Request(JSR) 202에서 2006년에 클래스 파일 형식 변경을 검토했다.
3. 파일 레이아웃 및 구조
자바 클래스 파일은 JVM이 실행할 수 있는 코드를 담고 있는 파일이다. 이 파일은 정해진 형식에 따라 구성되어 있으며, JVM은 이 형식을 이해하고 해석하여 프로그램을 실행한다.
클래스 파일은 가변 크기 항목을 포함하고 내장 파일 오프셋(또는 포인터)도 포함하지 않기 때문에, 일반적으로 첫 번째 바이트부터 끝까지 순차적으로 구문 분석된다. 파일 형식은 다음과 같은 몇 가지 기본 데이터 유형으로 설명된다.
* u1: 부호 없는 8비트 정수
* u2: 빅 엔디안 바이트 순서의 부호 없는 16비트 정수
* u4: 빅 엔디안 바이트 순서의 부호 없는 32비트 정수
* table: 특정 유형의 가변 길이 항목 배열. 테이블의 항목 수는 선행 개수 번호(개수는 u2)로 식별되지만, 테이블의 바이트 크기는 각 항목을 검사하여서만 결정할 수 있다.
이러한 기본 유형은 문맥에 따라 상위 수준 값(예: 문자열 또는 부동 소수점 숫자)으로 재해석된다. 클래스 파일은 워드 정렬을 강제하지 않으므로 패딩 바이트는 사용되지 않는다.
클래스 파일의 일반적인 레이아웃은 다음과 같다.
클래스 파일은 다음과 같은 주요 구성 요소들을 포함한다.
* [[매직 넘버 (프로그래밍)|매직 넘버]]: 파일을 자바 클래스 파일로 식별하는 고유한 값 (0xCAFEBABE)이다.
* 버전 정보: 클래스 파일 형식의 메이저 버전과 마이너 버전 번호이다.
* [[상수 풀]]: 클래스에서 사용되는 상수들을 저장하는 테이블이다.
* [[접근 플래그]]: 클래스의 접근 제어자 (public, private 등) 및 기타 속성 (abstract, final 등)을 나타내는 비트 마스크이다.
* 현재 클래스: 현재 클래스의 이름을 상수 풀에 대한 인덱스로 표현한다.
* [[슈퍼클래스 (컴퓨터 과학)|슈퍼 클래스]]: 부모 클래스의 이름을 상수 풀에 대한 인덱스로 표현한다.
* [[인터페이스 (객체 지향 프로그래밍)|인터페이스]]: 클래스가 구현하는 인터페이스들의 목록을 상수 풀에 대한 인덱스 배열로 표현한다.
* [[필드 (프로그래밍)|필드]]: 클래스의 멤버 변수(필드) 정보를 담고 있는 테이블이다.
* [[메서드 (컴퓨터 프로그래밍)|메서드]]: 클래스의 메서드 정보를 담고 있는 테이블이다.
* [[속성 (프로그래밍)|속성]]: 클래스 파일에 대한 추가적인 정보(예: 소스 파일 이름, 디버깅 정보 등)를 담고 있는 테이블이다.
3.1. 기본 섹션
자바 클래스 파일 구조에는 다음과 같은 10가지 기본 항목이 있다.
* 매직 넘버: 0xCAFEBABE
* 클래스 파일 형식의 버전: 클래스 파일의 마이너 및 메이저 버전
* 상수 풀: 클래스의 상수 풀
* 접근 플래그: 클래스가 추상적인지, 정적인지 등을 나타낸다.
* 현재 클래스: 현재 클래스의 이름
* 슈퍼 클래스: 슈퍼 클래스의 이름
* 인터페이스: 클래스 내의 모든 인터페이스
* 필드: 클래스 내의 모든 필드
* 메서드: 클래스 내의 모든 메서드
* 속성: 클래스의 모든 속성 (예: 소스 파일의 이름 등)
3.2. 매직 넘버
자바 클래스 파일은 4 바이트 헤더 (16진수) CA FE BA BE로 식별된다. 이 매직 넘버의 역사에 대해 제임스 고슬링은 팔로알토에 있는 한 식당을 언급하며 다음과 같이 설명했다:
> "우리는 St Michael's Alley라는 곳에서 점심을 먹곤 했습니다. 현지 전설에 따르면, 아주 오래전, 그레이트풀 데드는 유명해지기 전에 그곳에서 공연을 하곤 했습니다. 그곳은 정말 펑키한 곳이었고, 분명 그레이트풀 데드 스타일의 장소였습니다. 제리 가르시아가 죽었을 때는 작은 불교식 사당까지 세웠죠. 우리가 그곳에 갈 때, 우리는 그곳을 Cafe Dead라고 불렀습니다. 그러던 중, 이것이 16진수 숫자라는 것을 알게 되었습니다. 저는 파일 형식 코드를 개정하고 있었고, 몇 개의 매직 넘버가 필요했습니다. 하나는 영구 객체 파일용이고, 다른 하나는 클래스용이었습니다. 저는 객체 파일 형식에 CAFEDEAD를 사용했고, "CAFE" 뒤에 맞는 4글자 16진수 단어를 grep으로 찾다가 (좋은 테마 같아 보였습니다) BABE를 발견하고 사용하기로 결정했습니다. 그 당시에는 별로 중요하지 않거나 역사의 쓰레기통으로 갈 운명이라고 생각하지 않았습니다. 그래서 CAFEBABE가 클래스 파일 형식이 되었고, CAFEDEAD가 영구 객체 형식이 되었습니다. 그러나 영구 객체 기능은 사라졌고, CAFEDEAD의 사용도 함께 사라졌습니다. 결국 RMI로 대체되었습니다."
3.3. 일반적인 레이아웃
클래스 파일은 가변 크기 항목을 포함하고 내장 파일 오프셋(또는 포인터)도 포함하지 않기 때문에, 일반적으로 첫 번째 바이트부터 끝까지 순차적으로 구문 분석된다. 최하위 수준에서 파일 형식은 몇 가지 기본 데이터 유형으로 설명된다.
* u1: 부호 없는 8비트 정수
* u2: 빅 엔디안 바이트 순서의 부호 없는 16비트 정수
* u4: 빅 엔디안 바이트 순서의 부호 없는 32비트 정수
* table: 특정 유형의 가변 길이 항목 배열. 테이블의 항목 수는 선행 개수 번호(개수는 u2)로 식별되지만 테이블의 바이트 크기는 각 항목을 검사하여서만 결정할 수 있다.
이러한 기본 유형 중 일부는 문맥에 따라 상위 수준 값(예: 문자열 또는 부동 소수점 숫자)으로 재해석된다. 워드 정렬을 강제하지 않으므로 패딩 바이트는 사용되지 않는다. 클래스 파일의 전체 레이아웃은 아래 표와 같다.
3.4. 상세 레이아웃 테이블
클래스 파일은 가변 크기 항목을 포함하고 내장 파일 오프셋(또는 포인터)도 포함하지 않기 때문에, 일반적으로 첫 번째 바이트부터 끝까지 순차적으로 구문 분석된다. 최하위 수준에서 파일 형식은 몇 가지 기본 데이터 유형으로 설명된다.
* u1: 부호 없는 8비트 정수
* u2: 빅 엔디안 바이트 순서의 부호 없는 16비트 정수
* u4: 빅 엔디안 바이트 순서의 부호 없는 32비트 정수
* table: 특정 유형의 가변 길이 항목 배열. 테이블의 항목 수는 선행 개수 번호(개수는 u2)로 식별되지만, 테이블의 바이트 크기는 각 항목을 검사하여서만 결정할 수 있다.
이러한 기본 유형 중 일부는 문맥에 따라 상위 수준 값(예: 문자열 또는 부동 소수점 숫자)으로 재해석된다. 워드 정렬을 강제하지 않으므로 패딩 바이트는 사용되지 않는다. 클래스 파일의 전체 레이아웃은 다음 표와 같다.
4. C와 유사한 프로그래밍 언어에서의 표현
C는 구조체 내에서 가변 길이 배열을 지원하지 않으므로, 아래 코드는 컴파일되지 않으며 단지 예시로만 사용된다.
```c
struct Class_File_Format {
u4 magic_number;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count - 1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
};
5. 상수 풀
상수 풀은 자바 클래스 파일 구조에서 대부분의 리터럴 상수 값을 저장하는 곳으로, 숫자, 문자열, 식별자 이름, 클래스 및 메서드 참조, 타입 설명자 등을 포함한다. 상수 풀 내의 특정 상수에 대한 모든 인덱스나 참조는 16비트(u2 타입) 숫자로 제공되며, 인덱스 값 1은 테이블의 첫 번째 상수를 가리킨다(인덱스 값 0은 유효하지 않음).
파일 형식 개발 과정에서 이루어진 역사적 선택으로 인해, 상수 풀 테이블의 상수 수는 실제 개수와 다르다. 테이블은 1부터 시작하여 인덱싱되지만, 개수는 (최대 인덱스 + 1)로 해석해야 한다. 또한, long 및 double 타입의 상수는 테이블에서 두 개의 연속된 슬롯을 차지하지만, 두 번째 슬롯은 직접 사용되지 않는다.
5.1. 상수 타입 및 태그
상수 풀의 각 항목(상수) 유형은 첫 바이트인 '태그'로 식별된다. 이 태그 뒤에 오는 바이트 수와 그 해석은 태그 값에 따라 달라진다. 유효한 상수 유형과 해당 태그 값은 다음과 같다.
| 태그 바이트 | 추가 바이트 | 상수 설명 | 도입 버전 |
|---|---|---|---|
| 1 | 2+x 바이트 (가변) | UTF-8(유니코드) 문자열: 16비트 숫자(u2 타입)로 시작하는 문자열. 이 숫자는 바로 뒤에 오는 인코딩된 문자열의 바이트 수를 나타낸다(문자 수와 다를 수 있음). 사용된 인코딩은 실제 UTF-8이 아니며 유니코드 표준 인코딩 형식을 약간 수정했다. | 1.0.2 |
| 3 | 4 바이트 | 정수: 부호 있는 32비트 2의 보수 숫자로, 빅 엔디안 형식 | 1.0.2 |
| 4 | 4 바이트 | Float: 32비트 단정밀도 IEEE 754 부동 소수점 숫자 | 1.0.2 |
| 5 | 8 바이트 | Long: 부호 있는 64비트 2의 보수 숫자로, 빅 엔디안 형식(상수 풀 테이블에서 두 개의 슬롯을 차지함) | 1.0.2 |
| 6 | 8 바이트 | Double: 64비트 배정밀도 IEEE 754 부동 소수점 숫자(상수 풀 테이블에서 두 개의 슬롯을 차지함) | 1.0.2 |
| 7 | 2 바이트 | 클래스 참조: 완전한 클래스 이름(내부 형식)을 포함하는 UTF-8 문자열에 대한 상수 풀 내의 인덱스(빅 엔디안) | 1.0.2 |
| 8 | 2 바이트 | 문자열 참조: UTF-8 문자열에 대한 상수 풀 내의 인덱스(빅 엔디안) | 1.0.2 |
| 9 | 4 바이트 | 필드 참조: 상수 풀 내의 두 인덱스, 첫 번째는 클래스 참조를 가리키고, 두 번째는 이름 및 타입 설명자를 가리킴(빅 엔디안) | 1.0.2 |
| 10 | 4 바이트 | 메서드 참조: 상수 풀 내의 두 인덱스, 첫 번째는 클래스 참조를 가리키고, 두 번째는 이름 및 타입 설명자를 가리킴(빅 엔디안) | 1.0.2 |
| 11 | 4 바이트 | 인터페이스 메서드 참조: 상수 풀 내의 두 인덱스, 첫 번째는 클래스 참조를 가리키고, 두 번째는 이름 및 타입 설명자를 가리킴(빅 엔디안) | 1.0.2 |
| 12 | 4 바이트 | 이름 및 타입 설명자: 상수 풀 내의 UTF-8 문자열에 대한 두 인덱스, 첫 번째는 이름(식별자)을 나타내고 두 번째는 특별히 인코딩된 타입 설명자를 나타낸다. | 1.0.2 |
| 15 | 3 바이트 | 메서드 핸들: 이 구조는 메서드 핸들을 나타내는 데 사용되며, 타입 설명자 1바이트와 상수 풀 내의 인덱스로 구성된다. | 7 |
| 16 | 2 바이트 | 메서드 타입: 이 구조는 메서드 타입을 나타내는 데 사용되며, 상수 풀 내의 인덱스로 구성된다. | 7 |
| 17 | 4 바이트 | 동적: 부트스트랩 메서드 호출에 의해 생성된 동적으로 계산된 상수를 지정하는 데 사용된다. | 11 |
| 18 | 4 바이트 | InvokeDynamic: invokedynamic 명령에 의해 부트스트랩 메서드, 동적 호출 이름, 호출의 인수 및 반환 유형, 그리고 선택적으로 부트스트랩 메서드에 대한 정적 인수로 불리는 추가 상수 시퀀스를 지정하는 데 사용된다. | 7 |
| 19 | 2 바이트 | 모듈: 모듈을 식별하는 데 사용된다. | 9 |
| 20 | 2 바이트 | 패키지: 모듈에서 내보내거나 열린 패키지를 식별하는 데 사용된다. | 9 |
정수 상수 타입은 정수와 long 두 가지뿐이다. boolean, byte, short와 같이 상위 레벨 언어에 나타나는 다른 정수 타입은 정수 상수로 표현되어야 한다.
Java의 클래스 이름은 완전한 형태로 지정될 때 전통적으로 "java.lang.Object"와 같이 점으로 구분된다. 그러나 하위 레벨 클래스 참조 상수 내에서는 "java/lang/Object"와 같이 슬래시를 사용하는 내부 형식이 나타난다.
"UTF-8 문자열"이라는 명칭에도 불구하고, 유니코드 문자열은 실제로는 유니코드 표준에 따라 인코딩되지 않지만 유사하다. 두 가지 차이점이 있는데, (전체 논의는 UTF-8 참조) 첫 번째는 코드 포인트 U+0000이 표준 단일 바이트 인코딩 `00` 대신 2바이트 시퀀스 `C0 80`(16진수)으로 인코딩된다는 것이다. 두 번째 차이점은 보충 문자(U+10000 이상에서 BMP 외부의 문자)가 UTF-16과 유사한 서러게이트 쌍 구조를 사용하여 인코딩된다는 것이다. 이 경우 두 서러게이트 각각은 UTF-8로 개별적으로 인코딩된다. 예를 들어, U+1D11E는 올바른 4바이트 UTF-8 인코딩 `F0 9D 84 9E` 대신 6바이트 시퀀스
ED A0 B4 ED B4 9E로 인코딩된다.
6. 추가 문헌
* 팀 린드홀름, 프랭크 옐린, The Java Virtual Machine Specification, 2판 (프렌티스 홀, 1999년), ISBN 0-201-43294-3. JVM 및 클래스 파일 형식을 정의하는 공식 문서이다. 이 책의 초판과 2판 모두 [https://docs.oracle.com/javase/specs/ 온라인에서 무료로 열람 및 다운로드]할 수 있다.