클래스 파일

블러거·2026년 1월 23일

JVM

목록 보기
11/26
post-thumbnail

JVM 이 플랫폼 독립이 될 수 있었던 이유는 클래스 파일 덕분이다.
JVM 은 클래스 파일을 해석하여 실행하는 머신이고, 자바는 클래스 파일을 만들 수 있는 언어 중 하나다.

과거에는 리눅스, 윈도우 등 플랫폼에 독립적으로 아무 곳에서 작성해도 실행할 수 있는 것 이었지만, 이제는 언어 독립성도 생긴다. 코틀린, 자바, 스칼라 등 언어가 달라도 바이트 코드를 만들 수 있는 각각의 컴파일러가 있어서 JVM 에서 실행할 수 있는 코드를 언어 독립적으로 만들 수 있다.

이러한 것이 클래스 파일이라는게 있기 때문이며, 클래스 파일의 형태 및 규칙은 JDK1 부터 거의 바뀌지 않고 있다.

클래스 파일 구조

  • 구분자가 없는 바이트 스트림. 따로 구분자가 없기에 데이터가 작성되는 순서, 의기, 길이 등이 엄격하게 지켜져야 한다.
  • 1byte 단위로 작성
  • 클래스 파일이 저장하는 데이터(순서대로)
    • 매직 넘버와 클래스 파일의 버전
    • 상수 풀
    • 접근 플래그
    • 클래스 인덱스, 부모 클래스 인덱스, 인터페이스 인덱스
    • 필드 테이블
    • 메서드 테이블
    • 속성 테이블
  • 두가지 타입 존재
    • 부호 없는 숫자 : u1, u2, u4, u8 / 각각 1bytes 2bytes 4bytes 8bytes
    • 테이블 : 여러개의 부호 없는 숫자 또는 다른 테이블로 구성된 복합 데이터 타입. 관례적으로
      테이블 이름에 '_info' 접미어가 붙는다.
  • 같은 타입의 데이터 여러개를 표한할 때 수가 정해져 있지 않다면 개수를 알려주는 부호 없는 숫자 타입이 바로 앞에 등장한다. 이러한 데이터에는 '_count' 접미어가 붙는다.
  • 클래스파일은 꼭 파일 형태로 있지만은 않다. 런타임에 동적으로 생성되어 클래스 로더에 제공되는 이진 스트림 집합체도 JVM 에 올라가는 클래스 파일일 수 있다.

다음은 클래스 파일을 테이블 형태로 나타낸 것. 클래스 파일도 일종의 테이블이다.

ClassFile {
  u4                magic;
  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];
}

테스트 코드

이번 포스팅은

package classfiletest;

public class TestClass {
    private int x;
    private int y;

    public int sum() {
        return x + y;
    }

    public int sub(int z) {
        return x + y - z;
    }
}

코드(위)를 javac 로 컴파일 한 뒤 hex 편집기 로 해석한 16진수 값(아래) 와 비교하면서 공부 할 예정이다.

16진수 값은 1Byte 단위로 그룹핑되어 있는 모습이다.

javap -v 클래스파일 내용도 참고했다.

매직 넘버와 클래스 파일의 버전

매직 넘버
이 파일이 JVM 에서 사용하는 클래스 파일임을 나타내는 4Bytes(u4) 데이터. 이 파일이 클래스 파일인지 체크하는 용도. CAFEBABE 로 고정.

버전 번호
앞의 두 바이트(u2) = minor version
뒤의 두 바이트(u2) = major version

JDK1 은 Major Version 이 45 이다.
테스트 코드는 3D = 61 즉, JDK 17(61-45+1) 에서 컴파일 되었음을 알 수 있다.
마이너 버전은 대부분 0 으로 고정이다. JDK 1 의 일부와 12 에서 일부 기능의 베타 출시때 잠시 사용되었다.

상수 풀

클래스 파일에서 상수 풀

테스트 코드에서의 상수 풀 내용(length 표현 1개, 상수 23개)

상수 풀에서 쓰이는 타입의 17가지 테이블

필드 서술자, 메서드 서술자(descriptor)

  • 필드 서술자 : 데이터 타입
  • 메서드 서술자 : 매개 변수 목록(개수, 타입, 순서 포함), 반환 타입

상수 풀에서 서술자 상수는 다음 표와 같이 표시된다. 객체 타입의 경우 FQCN 앞에 L 을 붙인다.

배열 서술자는 차원 수 만큼 앞에 [ 가 붙는다. ex) int[] -> [I

필드 서술자의 경우 위 식별 문자 하나만 표시되나,
메서드 서술자는 N 개의 매개 변수 타입과 반환 타입 모두 나타내므로 규칙을 알아야 한다.
예시를 몇가지 적어보자면

  • void inc() -> ()V
  • java.lang.String.toString() -> ()Ljava/lang/String
  • int indexOf(Char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) -> ([CII[CIII)I
  • 클래스 내부에서 쓰이는 상수를 저장하는 테이블 구조 데이터
  • 상수 풀에 담기는 상수는 두가지 종류가 있다 : 리터럴 / 심벌 참조
    • 리터럴 : 자바에서로 치면 final로 선언된 문자열이나 상수
    • 심벌 참조
      • 모듈에서 임포트/익스포트 하는 패키지
      • 클래스와 인터페이스의 FQCN
      • 필드 이름과 서술자
      • 메서드 이름과 서술자
      • 메서드 핸들과 메서드 타입
      • 동적으로 계산되는 call site와 동적으로 계산되는 상수
  • 심벌 참조는 클래스 파일을 클래스 로더가 로드하고 클래스를 해석할 때 실제 메모리 주소로 변환한다.
  • 모든 데이터 타입은 u1 의 tag 값을 가진다. 자신 데이터 타입을 나타내는 id 라고 볼 수 있으며, 이걸 봐야 뒤에 나오는 몇개의 바이트 스트림이 어떤 의미인지 해석할 수 있다.
  • bytes 값들은 값 자체를 나타낸다.
  • index 값은 상수 풀의 상수를 1부터 순서대로 순번을 매겼을 때 해당 순서의 데이터의 포인터다. 이건 실제 예시를 보면 더 쉽다.
  • 가장 앞의 2bytes 는 상수 풀에 들어있는 상수의 개수이다. 예시에서는 0x18(=24) 이며 23개의 상수를 가지고 있다는 뜻
    • 이 개수 데이터는 특별히 개수를 1부터 세기에 실제 개수는 -1 해야 한다.
    • 0은 상수 풀 항목을 참조하지 않음을 표현해야하는 특수한 경우에 쓰임

실제 예시 해석

  • 위에서 상수를 모두 네모쳐놨다. 개수 데이터를 빼면 총 23개임을 볼 수 있다.
  • 첫번째 데이터는 0A 00 02 00 03. tag=0x0A 면 CONSTANT_Methodref_info 이다. 데이터 구조를 보면 CONSTANT_Class_infoCONSTANT_NameAndType_info 의 인덱스를 각각 u2 데이터로 가지고 있다. 즉 02 인덱스 상수가 CONSTANT_Class_info, 03 인덱스의 상수가 CONSTANT_NameAndType_info 이다.
    • 생성자 메서드다.
  • 두번째 상수가 CONSTANT_Class_info 인지 확인해보자. tag = 07 인 것을 확인할 수 있다. 실제 데이터가 07 00 04 이다. 04 인덱스에는 Utf8 상수 값이 들어있을 것이다.
    • 위에서 CONSTANT_Methodref_info -> CONSTANT_Class_info 로 왔으므로 인덱스 4에 있는 상수는 메서드 서술자의 완전한 이름 정보가 있을 것이다.
  • 네번째 상수는 tag = 01 인 CONSTANT_Utf8_info 이다. 실제 바이트 스트림은 01 00 10 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 이며 실제 데이터 영역만 디코딩해보면 java/lang/Object 이다.
    • 이런식으로 해석하며, 이 메서드 서술자가 어떤 메서드를 나타내는지 알기 위해선 첫번째 인덱스에 있는 데이터에서 CONSTANT_NameAndType_info 까지 따라가야 한다.

바이트 코드 상수값을 항상 이렇게 해석할순 없다.
javap -verbose TestClass
javap 는 클래스 파일 디스어셈블 명령이고, -verbose 옵션은 더 자세히 나타낸다.

이 명령을 실행하면 아래와 같이 상수풀을 쉽게 볼 수 있다.

CONSTANT_Utf8_info 의 length 가 u2 타입이다.
이는 2바이트이며 나타낼 수 있는 최대값은 65535 이다.
따라서 자바 프로그램에서 변수나 메서드의 이름은 64KB 를 넘으면 컴파일 되지 않는다.

접근 플래그

대상 클래스(인터페이스)의 접근제한자, final 등의 정보이다.
u2, 2Bytes 정보이며 비트로 정보를 나타낸다. 따라서 총 16개의 정보를 true/false 로 나타내며, 현재는 다음과 같이 9개 비트만 쓰인다.

ACC_SUPER 에 대해 보충설명 하자면, invokespeical 바이트코드 명령어는 JDK 1.0.2 버전 이전과 이후 명령어 의미가 다르다. JDK 1.0.2 이상이라면 항상 이 플래그는 true 다.

테스트 코드의 경우 public 클래스이기 때문에, 0x0001 | 0x0020 = 0x0021 임을 볼 수 있다.

클래스 인덱스, 부모 클래스 인덱스, 인터페이스 인덱스


  • 클래스 인덱스 : 상수 풀에서 클래스 정보를 가진 상수의 인덱스
  • 부모 클래스 인덱스 : 상수 풀에서 부모 클래스 정보를 가진 상수의 인덱스(바로 윗 부모만)
    • 다중 상속 안되므로 컬렉션이 아닌 하나
  • 인터페이스 인덱스 : 상수 풀에서 인터페이스 정보를 가진 상수의 인덱스
    • 인터페이스는 여러개 구현할 수 있으므로, _count 를 가진 컬렉션으로 표현

예시에서는 00 08 00 02 00 00 이다.
00 08 상수풀을 따라가면 classfiletest/TestClass 라는 클래스 이름이 나오고,
00 02 상수풀을 따라가면 java/lang/Object 라는 상위 클래스가 나온다. (상속을 선언하지 않았으므로 자바 기본 상위 클래스인 Object)
인터페이스 구현은 하지 않았으므로 00 00 으로 작성되었음을 알 수 있다.

필드 테이블


// 필드 테이블 구조
field_info {
  u2                access_flags;
  u2                name_index; // 필드 단순 이름의 상수풀 인덱스
  u2                descriptor_index; // 필드 서술자의 상수풀 인덱스
  u2                attributes_count;
  attribute_info    attributes[attributes_count];
}
  • 필드 테이블은 클래스 변수와 인스턴스 변수를 포함한다. 메서드 변수는 필드가 아니므로 표현되지 않는다.
  • 필드 테이블 부분은 필드 개수를 나타내는 fields_count(u2) 와 그 개수만큼의 field_info 테이블이 나열된다. 테스트의 경우 00 02 로 두개의 필드가 있다.
  • 상속받은 필드는 나열하지 않는다.
  • 중첩 클래스의 암묵적 this 처럼 코드에 나타나지 않고, 컴파일러가 자동으로 추가한 필드가 있을 수 있다.
  • 자바에서는 필드 이름이 같은 오버로딩을 할 수 없지만, 클래스 파일에서는 이름이 같고 서술자가 다른 두 필드는 다른 필드로 취급한다. 이를 이용하여 필드 오버로딩이 가능한 언어를 만들 수 도 있겠다.

access_flag

field_info 의 첫번째 항목이다. 접근제한자 외 필드에 붙을 수 있는 것들을 표시한다.

테스트에서 선언한 두 필드 모두 private 외에는 딱히 없으므로, 두 필드 모두 00 02 이다.

name_index, descriptor_index

다음은 필드 단순 이름과 필드 서술자의 상수 풀 인덱스이다.


00 0B 00 0C -> x:I
00 0F 00 0C -> y:I
위 상수풀과 같이 해석하면 필드의 FQCN 이 아닌 단순 이름 + 타입(I. Integer) 를 나타내는 상수 풀의 인덱스를 가진다.

attributes

만약 값이 초기화가 되어 있고 한다면 이 attribute 테이블에 명시된다.
이는 이후 속성 테이블에서 더 설명할 예정.

메서드 테이블


method_info {
  u2                access_flags;
  u2                name_index; // 메서드 단순 이름의 상수풀 인덱스
  u2                descriptor_index; // 메서드 서술자의 상수풀 인덱스
  u2                attributes_count;
  attribute_info    attributes[attributes_count];
}

좀 길지만, 메서드 세개(00 03) 과 이후 세개의 메서드를 빨간색 네모로 구분했다. 생성자 1개와 선언된 메서드 2개가 그 내용이다.

  • 메서드 테이블은 필드 테이블과 형태가 같다.
  • 자동으로 만들어지는 메서드가 있을 수 있다. <init>(), <cinit>() 이 그 예다.
  • 자바에서 메서드 오버로딩 판단에는 반환 타입이 들어가지 않는다. 즉, 자바에서는 메서드 이름과 매개변수가 같은데 반환 타입을 다르게 하여 오버로딩 할 수 없다. 반면 클래스 파일에서는 반환 타입 서술자만 다르게 하는것이 문제되지 않는다.

access flags

클래스 파일 레벨 Attributes


attribute 는 뒤에서 자세히 설명하겠다. 여기서는 테스트 클래스의 내용만 설명해보자.

  • 00 01 : 클래스 파일 레벨의 attributes count. 1개
  • 00 16 : attribute_name_index. 상수 풀에서 0x16(22) 를 조회하면 SourceFile 이 있다.
  • 00 00 00 02 : 속성 테이블 길이
  • 00 17 : 상수 풀의 0x17(23) 인덱스에는 TestClass.java 가 있다. 이 소스 파일의 이름이다.

Attributes

위에 나오지 않은 메서드의 연산 로직이라던지, 애너테이션, 런타임 디버깅에 사용할 줄번호 등은 어디에 있을까.
또 비교적 최근에 나온 sealed class, record class, module 임을 나타내는 정보는 어디 있을까.

이런 나머지 정보들이 들어가는 곳이 Attributes 다.

Attributes 는 아래 명시한 총 5가지의 사용처에서 각각 사용처를 설명하기 위한 값들이 들어간다. 예를들어 클래스 파일 attribute 로 Record Attributes 가 포함된다면 해당 클래스는 레코드 클래스임을 클래스파일에서 명시한 것이다.

Attributes 종류

JDK25 기준 클래스파일 구조에서 Attributes 는 총 30가지이다.

각각의 Attribute 는 사용처가 다르다. 예를 들어 Code Attribute 는 메서드 테이블에서만 쓰인다. 반면 애너테이션을 표현하는 RuntimeVisibleAnnotation Attribute 는 클래스 파일, 메서드 테이블, 필드 테이블, Record Attribute 의 record_component_info 에서 공통적으로 쓰일 수 있는 속성이다.

Attributes 사용처

JDK25 기준 클래스파일 구조에서 Attributes 타입을 쓰는 곳은 다섯곳이다.

Attributes 공통 구조

attribute_info {
  u2 attribute_name_index;
  u4 attribute_length;
  u1 info[attribute_length];
}

Attribute 는 위의 공통 구조 하에서 각각 다른 형태를 가진다.
각 Attribute 가 다른 구조이지만 위 구조는 공통적으로 포함한다.

Code 속성

Code_attribute {
    u2 attribute_name_index; // Code 상수를 가지고 있는 상수 풀의 인덱스
    u4 attribute_length; // 이후 나올 모든 Code Attribute 의 길이
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

코드 속성은 어쩌면 가장 중요한 속성이다. 메서드 테이블의 Attribute 로 존재하며, 메서드의 바이트 코드 명령어를 담고 있다.

  • max_stack : 피연산자 스택의 최대 깊이. 메서드 실행 중 이 스택의 깊이를 절대 넘을 수 없으며, 가상 머신은 깊이가 이 값만큼인 피연산자 스택을 스택 프레임에 할당
  • max_local : 지역 변수 테이블에 필요한 저장소 공간. 단위는 변수 슬롯(32비트. long, double 은 슬롯 두개 차지). 지역 변수의 개수가 아니라 슬롯 개수임을 유의. 지역 변수 테이블에는 매개 변수(this 포함), try-catch 매개 변수 예외, 지역 변수 모두 들어간다. 또한 이 값은 단순 지역 변수 테이블에 들어갈 요소 개수가 아니다. jvm 은 메모리를 절약하기 위해 슬롯을 최소한으로 만들어 재사용한다. 따라서 동시에 존재해야 하는 최대값을 max_local 로 정한다.
  • code_length : 코드 길이. u4 이지만 jvm 명세에 65535 라 정해져서 이를 넘을 수 없다. 사실상 u2 타입이다.
  • code : 실제 바이트 코드 명령어 스트림이다. 바이트 코드 명령어는 u1 이며, 실제로 바이트코드는 1바이트가 표현한 256개 이하이다. 각 바이트 코드 명령어는 1바이트 OpCode 와 맵핑되어 있다.
    이 부분을 해석할 때에는 명령어의 바이트도 필요하지만 명령어가 매개 변수를 필요로 하는가도 알아야 함. 예를 들어 invokespecial 같은 경우 뒤에 2바이트의 매개변수가 따라온다. 매개변수는 상수 풀의 인덱스 값이 적힌다.
    • 명령어가 실행되어야 하는 순서대로 클래스 파일에 작성된다.

javap -verbose 를 통해 code 를 보면 args_size 도 나온다.
메서드 매개 변수의 개수이며, 메서드 서술자로 계산된 값이다.
this 도 암묵적으로 들어가기 때문에 인스턴스 메서드의 경우 기본적으로 매개 변수가 없다면 1이다.
Static 메서드의 경우 this 가 없기에 매개 변수가 없다면 0이다.

  • exception_table : 예외 처리 구문이 있는 경우 이 테이블이 생성된다. 예외 처리 대상 바이트코드 명령어 인덱스 범위(try 블록)인 start_pc 와 end_pc, 예외 처리 코드 (catch 블록) 인 handler_pc, 그리고 예외 타입인 catch_type 네가지 필드를 가진 테이블이 try-catch-finally 구문 개수만큼 클래스 파일에 만들어진다. (아래 예시와 같이)

그외

  • Exceptions : 메서드 레벨에 throws 로 명시된 예외 정보
  • LineNumberTable : 코드 라인넘버와 바이트 코드 오프셋의 매핑이다. 이 기능 덕분에 예외시 스택 트레이스에 라인 넘버가 나오며, 디버깅시 중단점을 적용할 수 있다.
    • javap 에 LineNumberTable 과 Code Attribute 를 같이 보면 어떤 라인에서 어떤 바이트 코드 명령어가 쓰인건지 알 수 있다.
  • LocalVariableTable : Code 의 속성으로, 지역 변수 테이블 안의 변수와 소스 코드의 변수 사이의 관계를 나타낸다. 지역 변수 유효 범위 바이트 코드 인덱스와 변수 이름, 서술자가 있고 지역 변수 테이블에서의 슬롯 인덱스가 있다.
    • 이 정보를 통해 외부에서 매서드 사용시 매개 변수의 이름을 알 수 있다. 이게 없으면 arg0 이런식으로 보임
    • 책에는 기본 활성화 된다 되어있는데... 나는 javac -g 옵션을 줘서 컴파일해야 보인다.
    • Code 의 속성이므로 Code 속성이 없는 abstract 클래스의 메서드나 인터페이스 메서드의 매개 변수를 포함할 수 없다. 이를 해결하려면 MethodParameters 속성을 사용한다.
  • LocalVariableTypeTable : LocalVariableTable 와 같은 내용이나 제네릭 매개 변수용이다. 제네릭이라 Code 속성이 아닌 클래스 파일 속성이다.(제네릭은 클래스 객체 단위로 정해지니) 타입 소거 때문에 서술자는 매개 변수화 된 타입 정보를 담을 수 없으므로 따로 만들었다.
  • SourceFile : 파일 이름이다. 이게 없으면 예외 발생시 어느 파일에서 발생했는지 보이지 않는다.
  • ConstantValue : 필드 테이블의 속성이다. 정적 변수(클래스 변수, static) 에 본인이 가진 상수 풀 인덱스의 값을 초기화 하라고 알리는 역할
    • 클래스 변수는 클래스 생성자인 <clint>() 또는 ConstantValue 속성 중 하나를 사용해서 초기화할 수 있다. 오라클 javac 는 final static 중 기본타입과 String 을 ConstantValue 를 만들어 준다.
    • final static 변수에 ConstantValue 를 만들긴 하지만 해당 필드에 ACC_FINAL 플래그가 켜지진 않는다. 자바 가상 머신 명세에는 ACC_STATIC 만 활성화 하도록 명시하였고, 오라클 javac 가 final static 에 대해 만든다는건 컴파일러에서 구현된 제약이다.
    • ConstantValue 의 속성은 상수 풀의 인덱스를 가진다. 따라서 클래스 변수 중 객체 타입은 ConstantValue 를 통해 초기화할 수 없기에 오라클이 그렇게 만든 것.
  • InnerClasses : 내부 클래스들과 호스트 클래스의 관계
  • Deprecated : 내용이 boolean 인 속성. @Deprecated 에 생성됨
  • Synthetic : 내용이 boolean 인 속성. 컴파일러가 자동으로 추가한 필드나 메서드를 표현.
    • ex) enum 의 원소 배열, 중첩 클래스의 브릿지 메서드
    • <clinit>(), <init>() 는 자동으로 만들어지긴 하지만 예외
  • StackMapTable : Code 의 속성. 클래스 로딩시 파일의 타입 검증기에서 타입 검사와 적법성 검사에 사용. JDK5 까지의 타입 추론 검사기를 대체하여 성능이 좋아진 역사적인 그런..
  • Signature : 클래스 파일, 필드 테이블, 메서드 테이블 다 가능. 제네릭 시그니처 정보를 담음. 이거 덕분에 리플렉션으로 제네릭 타입 정보를 얻을 수 있음.
  • BootstrapMethods : 클래스 파일 속성. invokedymanic 명령어가 참조하는 부트스트랩 메서드 한정자가 담긴다.
  • MethodParameters : 메서드 테이블의 속성이다. 메서드 파라미터의 이름이 담긴다. LocalVariableTable 이 Code 속성에 있어서 추상 메서드나 인터페이스 메서드의 매개 변수를 표현할 수 없음을 보완하기 위해 만들어졌다.
    • 컴파일시 -parameters 옵션을 명시적으로 줘야 한다. (기본적으로 생성되지 않는다)
    • 이를 통해 리플렉션으로 메서드 이름을 가져올 수 있다.
      • 아래 예시 코드 [1] 의 코드를 -parameters 컴파일 옵션을 주고 안주고 차이를 보자. 출력에 이름이 args0 이렇게 보이다가 실제 매개 변수 이름이 보일 것.
    • jar 파일 만들때 이 옵션 없이 만들면 사용자가 불편할 것. spring 을 gradle 로 jar 파일 빌드하면 이 옵션이 자동으로 들어간다. (빌드 파일을 javap 로 보면 이 속성이 있음)
  • RuntimeVisibleAnnotations, RuntimeInvisibleAnnotations, RuntimeVisibleParameterAnnotations, RuntimeInvisibleParameterAnnotations : 애너테이션 정보를 담는다. 리플렉션으로 애너테이션 정보를 가져올 때 사용된다.
  • Record : 클래스 파일 속성이며, 해당 클래스가 Record Class 임을 나타낸다.
  • PermittedSubclasses : 클래스 파일 속성이며, 해당 클래스가 Sealed Class 임을 나타낸다.
    • 허용하는 클래스의 상수 풀 인덱스 목록을 가진다.
    • Sealed Class 는 자신 내부에서만 하위 클래스를 가질 수 있는 상위 클래스다. 따라서 하위 클래스가 딱 정해져서 코틀린에서는 switch 에서 else 를 쓰지 않아도 되는 그런 부가적인 이점이 있다.

예시 코드

[1]

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class TestInterface {
    public static void main(String[] args) throws Exception {
        Method m = TestInterface.class.getDeclaredMethod(
                "transfer",
                String.class, String.class, long.class
        );

        System.out.println("=== parameter info ===");
        for (Parameter p : m.getParameters()) {
            System.out.println(
                    "name=" + p.getName()
                            + ", isNamePresent=" + p.isNamePresent()
            );
        }
    }

    static void transfer(String fromUserId,
                         String toUserId,
                         long amount) {
        // no-op
    }
}
profile
안녕하세요!

0개의 댓글