ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 타입 이레이저
    카테고리 없음 2024. 7. 30. 20:16

    제네릭과 타입 이레이저

     

    다음은 제네릭의 특징 중 하나이다.

    제네릭은 비구체화(non-reify) 타입이다. 비구체화란, 런타임에는 소거(erasure)가 되기 때문에 컴파일 타임보다 정보를 적게 가지는 것을 의미한다.

     

    여기에서, erasure의 개념이 나온다.

    타입 이레이저는 자바 컴파일러(JVM)가 컴파일 단계에서 제네릭 코드에서 타입정보를 제거하는 과정이다.

    이는 자바 런타임 환경에서 호환성을 유지하고, 코드의 일관성을 보장하기 위해 사용한다. 또한, 제네릭이 사용되기 이전 버전(Java 5 이전) 과 호환이 가능하도록 한다.

     

    자바 컴파일 단계의 erasure

    1. unbounded type(<?>, <T>)은 Object 형으로 바꾼다.

    public class GenericBox<T> {
    
        private T value;
    
        public void set(T value) {
            this.value = value;
        }
    
        public T get() {
            return value;
        }
    }

     

    public class GenericBox<Object> {
    
        private Object value;
    
        public void set(Object value) {
            this.value = value;
        }
    
        public Object get() {
            return value;
        }
    }

     

    2. bounded type상한 타입으로 바뀐다.

    public class Complexbox <T extends Animal> {
    
        private  T animal;
    
        public void set(T animal) {
            this.animal = animal;
        }
    
        public <T> T printAndReturn(T t) {
            System.out.println("animal.className:" + animal.getClass());
            System.out.println("t.className: " + t.getClass().getName());
            return t;
        }
    }
    public class Complexbox {
    
        private  Animal animal;
    
        public void set(Animal animal) {
            this.animal = animal;
        }
    
        public Animal printAndReturn(Animal t) {
            System.out.println("animal.className:" + animal.getClass());
            System.out.println("t.className: " + t.getClass().getName());
            return t;
        }
    }

     

    3. 확장된 제네릭 타입에서 다형성을 보존하기 위해 bridge method를 생성한다.

    public class MyCalculator implements Calculator<Integer> {
        public int compare(Integer a, Integer b) {
            
        }
    }
    
    public class MyCalculator implements Calculator {
        public int compare(Integer a, Integer b) {
    
        }
    }
    // bridge method
    public int compare(Object a, Object b) {
        return compare((Integer)a, (Integer)b);
    }

     

    4. 리턴 타입에 맞춰 자바 컴파일러가 자동으로 캐스팅 코드를 넣어준다.

    public class AnimalHospital<T extends Animal> {
         private T animal;
         public void set(T animal) {
             this.animal = animal;
    }
        public T getBigger(T target) {
         return animal.getSize() > target.getSize() ? animal : target;
        } 
    }
    
    // 상한 타입으로 변경 후
    public class AnimalHospital {
         private Animal animal;
         public void set(Animal animal) {
             this.animal = animal;
    }
        public Animal getBigger(Animal target) {
         return animal.getSize() > target.getSize() ? animal : target;
        } 
    }

    T 의 타입 정보가 제거되어도 상한으로 지정한 Animal 타입으로 대체되기 때문에 Animal 타입의 메서드를 사용하는데는 아무런 문제가 없다.

    AnimalHospital hospital = new AnimalHospital();
    
    // 타입 캐스팅
    Dog dog = (Dog) animalHospital.getBigger(new Dog());

    반환 받는 부분을 Animal 로 받으면 안되기 때문에 자바 컴파일러가 타입 인자로 지정한 Dog 로 캐스팅하는 코드를 넣어준다.

     

    자바의 제네릭은 단순하게 생각하면 개발자가 직접 캐스팅 하는 코드를 컴파일러가 대신 처리해주는 것이다. 

     

    제네릭 타입 이레이저 역할

     

    1. 타입 정보 제거: 자바 컴파일러는 컴파일 단계(인스턴스 화)에서 제네릭 코드의 타입정보를 제거한 후, 원시 타입으로 대체한다. 예를 들어 HashMap<String> 타입을 HashMap 으로 대체한다.

     

    2. 타입 안정성 보장: 자바 컴파일 단계에서 타입 체크를 수행하여 런타임시 에러 발생을 방지한다. 

     

    3. 바이트코드 호환성 유지: 타입 이레이저는 통해 제네릭 코드를 기존 비제네릭 코드와 호환되도록 한다.

     

     

    제네릭 타입 이레이저 한계

    컴파일 이후에는 제네릭의 타입 정보가 존재하지 않는다. `.class` 로 자바를 실행하는 런타임에는 타입 정보가 모두 제거된다.

     

    1. instanceof

    public boolean instanceCheck(Object param) 
    { 
        return param instanceof T;
    }
    
    public void create() 
    { 
    	return new T();
    }
    
    // 다음 메소드는 언제나 참을 반환
    public boolean instanceCheck(Object param) 
    { 
    	return param instanceof Object; // 오류
    }

     

    타입 이레이징을 거친 다음 메소드는 언제나 Object와 객체를 비교하여 항상 참이 반환되는 문제가 발생한다.

     

    2. new 생성자

    public void create() 
    { 
    	return new T(); // 오류
    }
    public void create() 
    {
    	return new Object(); // 오류
    }

     

    new T() 는 항상 new Object() 가 되어 개발자가 의도한 객체 생성자와 다르게 동작한다.

     

     

    https://velog.io/@dorameme/Java-%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%83%80%EC%9E%85%EC%9D%B4%EB%A0%88%EC%9D%B4%EC%A0%80%EB%8A%94-%EC%99%9C-%ED%95%84%EC%9A%94%ED%95%A0%EA%B9%8C

     

    Java) 제네릭 타입이레이저는 왜 필요할까?

    제네릭 타입 이레이저(Type Erasure)는 자바 컴파일러가 제네릭 코드에서 타입 정보를 제거하는 과정이다. 이는 자바 런타임 환경에서의 호환성을 유지하고, 코드의 일관성을 보장하기 위해 필요하

    velog.io

     

     

Designed by Tistory.