자바(SE)

[java] Skip "synthetic" methods when stepping

  • -

java debugger 설정 과정에서 "Skip synthetic methods when stepping" 항목이 있는데 과연 이 synthetic method가 무엇인지 살펴보자.

이번 포스트는 Synthetic Constructs in Java | Baeldung를 참조해서 작성되었습니다. 참고로 synthetic method나 synthetic constructor는 JDK 11 부터는 없어졌다고 한다.

Synthetic Constructs in Java | Baeldung

 

synthetic ?

synthetic 즉 합성이라는 말은 하기는 쉽지만 쉽게 받아들여지지는 않는 개념이다. 자바에서 합성된 요소는 컴파일 결과물 중에서 소스 코드에 대응하는 구성 요소가 없는 구성 요소 중 기본 생성자, 클래스 초기화 메서드, Enum 클래스의 values나 valueOf 메서드를 제외한 것들을 이야기 한다.

이런 합성요소의 종류는 field, method, constructor가 있다.

 

synthetic field

아래와 같은 코드를 생각해보자.

import java.lang.reflect.Field;

public class SyntheticTest {
    private class Inner {
        String name;
    }

    public static void main(String[] args) {
        SyntheticTest test = new SyntheticTest();
        test.syntheticFieldTest();
    }

    public void syntheticFieldTest() {
        Field[] fields = SyntheticTest.Inner.class.getDeclaredFields();

        for (Field f : fields) {
            System.out.println("필드: isSynthetic: " + f.isSynthetic() + " : " + f);
        }
    }
}

SyntheticTest에는 Inner 라는 내부 클래스를 가지고 있고 Inner에는 String 타입의 name이 하나가 선언되어있다. syntheticFieldTest 메서드에서는 reflection api를 이용해서 Inner class에 선언된 field들을 출력해보고 있는데.. 출력된 결과를 살펴보면 .............................충격적으로 field는 두개다!!

필드: isSynthetic: false : java.lang.String etc.synthetic.SyntheticTest$Inner.name
필드: isSynthetic: true : final etc.synthetic.SyntheticTest etc.synthetic.SyntheticTest$Inner.this$0

우리가 선언하지 않았지만 생성된 this$0 가 바로 synthetic field가 된다. 이 field를 통해서 Inner class는 외부 클래스인 SyntheticTest를 참조하는 것이었다.!!!

이것만 봐도 synthetic의 개념을 쉽게 이해할 수 있을 것이다.

 

synthetic method

그럼 synthetic method는? 당연히 필요에 의해 컴파일러가 자동으로 삽입해놓은 메서드이다. SyntheticTest에 다음의 메서드를 추가해보자.

public class SyntheticTest {
    class Inner {
        private String name;
    }

    public void useInnerMember() {
        Inner inner = new Inner();
        inner.name = "홍길동";
        System.out.println(inner.name);
    }
}

Inner의 name은 private인데 어떻게 외부에 있는 SyntheticTest에서 바로 name을 접근할 수 있었을까? (외부에서 내부에 접근할 때는 접근제한자와 상관 없이 접근 가능하다고 외웠었는데... )

그 이유는 역시 synthetic method가 개입되기 때문이다. SyntheticTest에 아래 처럼 메서드를 추가하고 Inner가 가진 메서드들을 조사해보자.

public void syntheticMethodTest() {
    Method[] methods = SyntheticTest.Inner.class.getDeclaredMethods();

    for (Method m : methods) {
        System.out.println("메서드: isSynthetic: " + m.isSynthetic() + " : " + m);
    }
}

출력 결과를 살펴보면..

메서드: isSynthetic: true : static void etc.synthetic.SyntheticTest$Inner.access$0(
                                     etc.synthetic.SyntheticTest$Inner,java.lang.String)
메서드: isSynthetic: true : static java.lang.String etc.synthetic.SyntheticTest$Inner.access$1(
                                     etc.synthetic.SyntheticTest$Inner)

우리가 선언하지 않았던 두 개의 메서드가 생성된 것을 볼 수 있는데 눈치 빠른 사람은 access$0가 setter의 역할을 수행하고 access$1은 getter 역할을 수행하고 있음을 알 수 있다.

이처럼 자동으로 삽입된 메서드가 synthetic method가 된다.

 

결론

옵션 설정이 궁금해서 찾아봤지만 전술했듯이 JDK 11 부터는 synthetic method나 synthetic constructor가 생성되지 않으니 컴파일러의 옵션도 무의미해졌다고 볼 수 있다.

물론 JDK 1.8 에서는 디버깅 과정에서 이런 synthetic method를 건너뛰는 것이 조금이나마 번거로움을 피할 수 있는 길이긴 하다.

 

 

'자바(SE)' 카테고리의 다른 글

[람다표현식]Lambda 표현식  (0) 2022.07.11
[람다표현식]inner class  (0) 2022.07.11
[Java]List의 subList 살펴보기!  (2) 2022.02.10
[Java]Thread의 선/후 작업과 CountDownLatch  (0) 2021.02.16
Comparing identical expressions  (0) 2021.01.16
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.