1. 개요
이 예제에서는 불충분 한 가시성 또는 누락 된 참조로 인해 도달 할 수없는 멤버에 대한 액세스를 투명하게 처리하기 위해 컴파일러가 도입 한 코드 인 Java의 합성 구조를 살펴볼 것입니다.
참고 : JDK 11 부터 합성 메서드 및 생성자는 중첩 기반 액세스 제어로 대체되므로 더 이상 생성되지 않습니다 .
2. 자바의 합성
우리가 찾을 수있는 가장 좋은 합성 정의 는 Java 언어 사양 ( JLS 13.1.7 ) 에서 직접 가져온 것입니다 .
기본 생성자, 클래스 초기화 메서드, Enum 클래스의 값 및 valueOf 메서드를 제외하고 소스 코드에 해당 구조가없는 Java 컴파일러에 의해 도입 된 모든 구조는 합성으로 표시되어야합니다.
여러 종류의 컴파일 구성, 즉 필드, 생성자 및 메서드가 있습니다. 반면에 중첩 된 클래스는 컴파일러 (즉, 익명 클래스)에 의해 변경 될 수 있지만 합성으로 간주되지 않습니다 .
더 이상 고민하지 않고 각각에 대해 자세히 살펴 보겠습니다.
3. 합성 분야
간단한 중첩 클래스부터 시작하겠습니다.
public class SyntheticFieldDemo {
class NestedClass {}
}
컴파일되면 모든 내부 클래스에는 최상위 클래스를 참조 하는 합성 필드가 포함됩니다 . 우연히도 이것은 중첩 된 클래스에서 둘러싸는 클래스 멤버에 액세스 할 수있게합니다.
이것이 일어나고 있는지 확인하기 위해 리플렉션에 의해 중첩 된 클래스 필드를 가져오고 isSynthetic () 메서드를 사용하여 확인하는 테스트를 구현합니다 .
public void givenSyntheticField_whenIsSynthetic_thenTrue() {
Field[] fields = SyntheticFieldDemo.NestedClass.class
.getDeclaredFields();
assertEquals("This class should contain only one field",
1, fields.length);
for (Field f : fields) {
System.out.println("Field: " + f.getName() + ", isSynthetic: " +
f.isSynthetic());
assertTrue("All the fields of this class should be synthetic",
f.isSynthetic());
}
}
이를 확인할 수있는 또 다른 방법은 javap 명령을 통해 디스어셈블러를 실행하는 것 입니다. 두 경우 모두 출력에 this $ 0 이라는 합성 필드가 표시 됩니다.
4. 합성 방법
다음으로 중첩 클래스에 private 필드를 추가합니다.
public class SyntheticMethodDemo {
class NestedClass {
private String nestedField;
}
public String getNestedField() {
return new NestedClass().nestedField;
}
public void setNestedField(String nestedField) {
new NestedClass().nestedField = nestedField;
}
}
이 경우 컴파일은 변수에 대한 접근자를 생성합니다. 이러한 메서드가 없으면 둘러싸는 인스턴스에서 개인 필드에 액세스 할 수 없습니다.
다시 한 번 access $ 0 및 access $ 1 이라는 두 가지 합성 메서드를 보여주는 동일한 기술로이를 확인할 수 있습니다 .
public void givenSyntheticMethod_whenIsSynthetic_thenTrue() {
Method[] methods = SyntheticMethodDemo.NestedClass.class
.getDeclaredMethods();
assertEquals("This class should contain only two methods",
2, methods.length);
for (Method m : methods) {
System.out.println("Method: " + m.getName() + ", isSynthetic: " +
m.isSynthetic());
assertTrue("All the methods of this class should be synthetic",
m.isSynthetic());
}
}
통지 코드를 생성하기 위해, 필드가 실제로에서 읽을 수 있어야합니다 또는 기록은 , 그렇지 않으면, 방법은 멀리 최적화됩니다 . 이것이 우리가 getter와 setter를 추가 한 이유입니다.
위에서 언급했듯이 이러한 합성 방법은 더 이상 JDK 11부터 생성되지 않습니다.
4.1. 브리지 방법
합성 메서드의 특별한 경우는 제네릭의 유형 삭제를 처리하는 브리지 메서드입니다.
예를 들어 간단한 비교기를 생각해 봅시다 .
public class BridgeMethodDemo implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
return 0;
}
}
하지만 () 비교 이 개 소요 정수 소스에 인수를 컴파일하면 두 개의 할게요 개체 삭제를 입력하기 때문에 대신 인수를.
이를 관리하기 위해 컴파일러는 인수 캐스팅을 처리하는 합성 브리지를 만듭니다 .
public int compare(Object o1, Object o2) {
return compare((Integer) o1, (Integer) o2);
}
이전 테스트 외에도 이번에는 Method 클래스 에서 isBridge () 를 호출합니다 .
public void givenBridgeMethod_whenIsBridge_thenTrue() {
int syntheticMethods = 0;
Method[] methods = BridgeMethodDemo.class.getDeclaredMethods();
for (Method m : methods) {
System.out.println("Method: " + m.getName() + ", isSynthetic: " +
m.isSynthetic() + ", isBridge: " + m.isBridge());
if (m.isSynthetic()) {
syntheticMethods++;
assertTrue("The synthetic method in this class should also be a bridge method",
m.isBridge());
}
}
assertEquals("There should be exactly 1 synthetic bridge method in this class",
1, syntheticMethods);
}
5. 합성 생성자
마지막으로 개인 생성자를 추가합니다.
public class SyntheticConstructorDemo {
private NestedClass nestedClass = new NestedClass();
class NestedClass {
private NestedClass() {}
}
}
이번에는 테스트 또는 디스어셈블러를 실행하면 실제로 두 개의 생성자가 있으며 그중 하나는 합성입니다.
public void givenSyntheticConstructor_whenIsSynthetic_thenTrue() {
int syntheticConstructors = 0;
Constructor<?>[] constructors = SyntheticConstructorDemo.NestedClass
.class.getDeclaredConstructors();
assertEquals("This class should contain only two constructors",
2, constructors.length);
for (Constructor<?> c : constructors) {
System.out.println("Constructor: " + c.getName() +
", isSynthetic: " + c.isSynthetic());
if (c.isSynthetic()) {
syntheticConstructors++;
}
}
assertEquals(1, syntheticConstructors);
}
합성 필드와 마찬가지로이 생성 된 생성자는 둘러싸는 인스턴스의 전용 생성자로 중첩 된 클래스를 인스턴스화하는 데 필수적입니다.
위에서 언급했듯이 합성 생성자는 더 이상 JDK 11부터 생성되지 않습니다.
6. 결론
이 기사에서는 Java 컴파일러에 의해 생성 된 합성 구조에 대해 논의했습니다. 이를 테스트하기 위해 리플렉션을 사용 했습니다 . 여기에서 자세히 알아볼 수 있습니다 .
- https://docs.spring.io/spring-framework/docs/current/reference/html
- https://www.baeldung.com/java-synthetic
'Java' 카테고리의 다른 글
PowerMock 소개 (0) | 2021.03.20 |
---|---|
Big O 표기법의 실용적인 Java 예제 (0) | 2021.03.20 |
Jersey 애플리케이션에서 Spring Security를 사용한 소셜 로그인 (0) | 2021.03.19 |
Java에서 일정 시간 후에 실행을 중지하는 방법 (0) | 2021.03.19 |
Open Liberty 소개 (0) | 2021.03.19 |