1. 개요

이 빠른 기사에서는 유형 삭제로 알려진 Java 제네릭의 중요한 메커니즘에 대한 기본 사항에 대해 설명합니다.

2. 유형 삭제란 무엇입니까?

타입 삭제는 컴파일 타임 에만 타입 제약을 가하고 런타임에 요소 타입 정보를 버리는 과정으로 설명할 수 있습니다 .

예를 들어:

public static  <E> boolean containsElement(E [] elements, E element){
    for (E e : elements){
        if(e.equals(element)){
            return true;
        }
    }
    return false;
}

컴파일러는 바인딩되지 않은 유형 E 를 실제 유형의 Object로 바꿉니다 .

public static  boolean containsElement(Object [] elements, Object element){
    for (Object e : elements){
        if(e.equals(element)){
            return true;
        }
    }
    return false;
}

따라서 컴파일러는 코드의 형식 안전성을 보장하고 런타임 오류를 방지합니다.

3. 유형 삭제 유형

유형 삭제는 클래스(또는 변수) 및 메서드 수준에서 발생할 수 있습니다.

3.1. 클래스 유형 삭제

클래스 수준에서 컴파일러는 클래스의 형식 매개 변수를 버리고 첫 번째 바인딩으로 대체하거나 형식 매개 변수가 바인딩되지 않은 경우 Object로 바꿉니다 .

배열을 사용하여 스택구현해 보겠습니다 .

public class Stack<E> {
    private E[] stackContent;

    public Stack(int capacity) {
        this.stackContent = (E[]) new Object[capacity];
    }

    public void push(E data) {
        // ..
    }

    public E pop() {
        // ..
    }
}

컴파일 시 컴파일러는 바인딩되지 않은 형식 매개 변수 EObject 로 바꿉니다 .

public class Stack {
    private Object[] stackContent;

    public Stack(int capacity) {
        this.stackContent = (Object[]) new Object[capacity];
    }

    public void push(Object data) {
        // ..
    }

    public Object pop() {
        // ..
    }
}

유형 매개변수 E 가 바인딩된 경우:

public class BoundStack<E extends Comparable<E>> {
    private E[] stackContent;

    public BoundStack(int capacity) {
        this.stackContent = (E[]) new Object[capacity];
    }

    public void push(E data) {
        // ..
    }

    public E pop() {
        // ..
    }
}

컴파일러는 바인딩된 유형 매개변수 E 를 첫 번째 바인딩된 클래스( 이 경우 Comparable)로 바꿉니다 .

public class BoundStack {
    private Comparable [] stackContent;

    public BoundStack(int capacity) {
        this.stackContent = (Comparable[]) new Object[capacity];
    }

    public void push(Comparable data) {
        // ..
    }

    public Comparable pop() {
        // ..
    }
}

3.2. 메소드 유형 삭제

메서드 수준 형식 지우기의 경우 메서드의 형식 매개 변수는 저장되지 않고 바인딩되지 않은 경우 또는 바인딩될 때 첫 번째 바인딩된 클래스인 경우 부모 형식 Object 로 변환됩니다 .

주어진 배열의 내용을 표시하는 방법을 고려해 보겠습니다.

public static <E> void printArray(E[] array) {
    for (E element : array) {
        System.out.printf("%s ", element);
    }
}

컴파일 시 컴파일러는 E 유형 매개변수  를 Object 로 바꿉니다 .

public static void printArray(Object[] array) {
    for (Object element : array) {
        System.out.printf("%s ", element);
    }
}

바인딩된 메서드 유형 매개변수의 경우:

public static <E extends Comparable<E>> void printArray(E[] array) {
    for (E element : array) {
        System.out.printf("%s ", element);
    }
}

유형 매개변수 E를 지우고 Comparable 로 교체합니다 .

public static void printArray(Comparable[] array) {
    for (Comparable element : array) {
        System.out.printf("%s ", element);
    }
}

4. 엣지 케이스

형식 삭제 프로세스 중 컴파일러는 유사한 메서드를 구별하기 위해 합성 메서드를 만듭니다. 이는 동일한 첫 번째 바인딩된 클래스를 확장하는 메서드 서명에서 올 수 있습니다.

스택 의 이전 구현을 확장하는 새 클래스를 만들어 보겠습니다 이것은 java.util.Stack이 아니라 섹션 3.1 에서 생성 Stack 클래스를 나타냅니다 .

public class IntegerStack extends Stack<Integer> {

    public IntegerStack(int capacity) {
        super(capacity);
    }

    public void push(Integer value) {
        super.push(value);
    }
}

이제 다음 코드를 살펴보겠습니다.

IntegerStack integerStack = new IntegerStack(5);
Stack stack = integerStack;
stack.push("Hello");
Integer data = integerStack.pop();

유형 삭제 후 다음을 수행합니다.

IntegerStack integerStack = new IntegerStack(5);
Stack stack = (IntegerStack) integerStack;
stack.push("Hello");
Integer data = (String) integerStack.pop();

우리가 밀어 수있는 방법을 공지 S 트링IntegerStack을 하기 때문에 - IntegerStack가 상속 푸시 (Object)를 부모 클래스에서 스택 . 물론 이것은 잘못된 것입니다. integerStackStack<Integer> 유형 이므로 정수여야 하기 때문 입니다.

따라서 당연히 String 하고 Integer에 할당 하려고 하면 컴파일러 푸시 하는 동안 삽입된 캐스트에서 ClassCastException이 발생합니다 .

4.1. 브리지 방법

위의 경우를 해결하기 위해 컴파일러는 때때로 브리지 메서드를 만듭니다. 이것은 매개 변수화된 클래스를 확장하거나 메서드 서명이 약간 다르거나 모호할 수 있는 매개 변수화된 인터페이스를 구현하는 클래스 또는 인터페이스를 컴파일하는 동안 Java 컴파일러에 의해 생성된 합성 메서드입니다.

위의 예에서 Java 컴파일러는 IntegerStackpush(Integer) 메서드와 Stackpush(Object) 메서드 간에 메서드 서명 불일치가 없도록 하여 삭제 후 일반 유형의 다형성을 유지 합니다.

따라서 컴파일러는 여기에 브리지 메서드를 만듭니다.

public class IntegerStack extends Stack {
    // Bridge method generated by the compiler
    
    public void push(Object value) {
        push((Integer)value);
    }

    public void push(Integer value) {
        super.push(value);
    }
}

결과적으로 Stack 클래스의 push 메서드는 type 삭제 후 IntegerStack 클래스 의 원래 push 메서드에 위임됩니다 .

5. 결론

이 사용방법(예제)에서는 형식 매개 변수 변수 및 메서드의 예제를 사용하여 형식 지우기의 개념에 대해 논의했습니다.

다음 개념에 대해 자세히 알아볼 수 있습니다.

항상 그렇듯이 이 기사와 함께 제공되는 소스 코드는 GitHub에서 사용할 수 있습니다 .

Junit footer banner