Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

일상기록

Java - 제네릭 타입의 형변환 본문

Java

Java - 제네릭 타입의 형변환

너 구 나 2023. 4. 18. 11:02

제네릭 타입의 형변환

제네릭 타입과 원시 타입(raw type)간의 형변환이 가능할까? 아래 코드를 보면

Box box = null;
Box<Object> objBox = null;

box = (Box)objBox; // OK 제네릭 타입 → 원시 타입(안쓰는게 바람직) 경고발생
objBox = (Box<Object>)box; // OK 원시 타입(안쓰는게 바람직) → 제네릭 타입 경고발생

코드를 보면 알 수 있듯이, 제네릭 탕비과 논제네릭(non-generic) 타입간의 형변환은 항상 가능하다. 다만 경고가 발생할 뿐이다. 그렇다면 대입된 타입이 다른 제네릭 타입 간에 형변환은 가능할까?

Box<String> srtBox = null;
Box<Object> objBox = null;

srtBox = (Box<String>)objBox; // 에러 Box<Object> → Box<String> 
objBox = (Box<Object>)srtbox; // 에러 Box<String> → Box<Object>

불가능하다. 대입된 타입이 Object일지라도 말이다. 이 사실은 이미 배웠다. 아래의 코드가 안 된다는 얘기는 Box<String>이 Box<Object>로 형변환될 수 없다는 사실을 간접적으로 알려주는 것이다.

//Box<Object> objBox = (Box<Object>)new Box<String>(); // (Box<Object>) 생략가능
Box<Object> objBox = new Box<String>(); // 에러 형변환 불가능

그렇다면 Box<? extends Object>라면 형변환 가능할까?

Box<? extends Object> wBox = new Box<String>(); // OK

가능하다 다형성이 적용되는 것이다. 반대로의 형변환도 성립하지만 확인되지 않은 형변환이라는 경고가 발생한다.

실제 예시를 보면 java.util.Optional클래스의 실제 소스의 일부이다. 

public final class Optional<T> {
	private static final Optional<?> EMPTY = new Optional<>();
    private final T value;
    	...
    public static<T> Optional<T> empty(){
    	Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
    	...
}

static상수 EMPTY에 비어있는 Optional객체를 생성해서 저장했다가 empty()를 호출하면 EMPTY를 형변환해서 반환한다. 먼서 상수를 선언하는 문장을 보면 다음과 같다.

    Optional<?> EMPTY = new Optional<>();
→ Optional<? extends Object> EMPTY = new Optional<>();
→ Optional<? extends Object> EMPTY = new Optional<Object>();

<?>는 <? extends Object>를 줄여서 쓴 것이며, <>안에 생략된 타입은 '?'가 아니라 'Object'이다.

Optional<?> EMPTY = new Optional<?>();              // 에러 미확인  타입의 객체는 생성불가
Optional<?> EMPTY = new Optional<Object>();    // OK
Optional<?> EMPTY = new Optional<>();                // OK 위의 문장과 동일

위 문장에서 EMPTY의 타입을 Optional<Object>가 아니 Optional<?>로 한 이유는 Optional<T>로 형변환이 가능하기 때문이다.

Optional<?> wopt = new Optional<Object>();
Optional<Object> oopt = new Optional<Object>();

Optional<String> sopt = (Optional<String>)wopt; // OK 형변환 가능
Optional<String> sopt = (Optional<String>)oopt; // 에러 형변환 불가

empty()의 반환 타입이 Optional<T>이므로 EMPTY를 Optional<T>로 형변환해야 하는데, 위의 코드에서 알 수 있는 것처럼 Optional<Object>는 Optional<T>로 형변환이 불가능 하다.

public static<T> Optional<T> empty() {
	Optional<T> t = (Optional<T>) EMPTY; // Optional<?> → Optional<T> 
	return t;
}

정리하면, Optional<Object>를 Optional<String>으로 직접 형변환하는 것은 불가능하지만, 와일드 카드가 포함된 제네릭 타입으로 형변환하면 가능하다. 대신 확인되지 않은 타입으로의 형변환이라는 경고가 발생한다.

Optional<Object> → Optional<T>                         // 형변환 불가능
Optional<Object> → Optional<?> → Optional     // 형변환 가능, 경고발생

 마지막으로 다음과 같이 와일드 카드가 사용된 제네릭 타입 끼리도 다음과 같은 경우에는 형변환 가능하다.

FruitBox<? extend String> srtBox = null;
FruitBox<? extend Object> objBox = null;

srtBox = (FruitBox<? extend String>)objBox; // OK 미확정 타입으로 형변환 경고
objBox = (FruitBox<? extend Object>)srtbox; // OK 미확정 타입으로 형변환 경고

형변환이 가능하긴 하지만, 와일드 카드는 타입이 확정된 타입이 아니므로 컴파일러는 미확정 타임으로 형변환하는 것이라고 경고한다.

'Java' 카테고리의 다른 글

Java - 열거형(Enums)  (0) 2023.04.18
Java - 제네릭 타입의 제거  (0) 2023.04.18
Java - 제네릭 메소드  (0) 2023.04.18
Java - 와일드 카드  (0) 2023.04.17
Java - 제네릭(Generic)  (0) 2023.04.17