Java/문제 해결 (Troubleshooting)

java: incompatible types: T cannot be converted to capture#1 of ?

가지코딩 2025. 4. 21. 19:04

문제 상황

  • enum은 제네릭으로 만들 수 없음 
    • enum Operator<T extends Number> {}불가능
    • private final Operate<T> op 불가능
  • 하지만 op 는 값이 타입이 정해지지 않은, 알 수 없는 타입
  • 때문에 와일트 카드(?)를 사용했으나, T를 ?에 넣을 수 없음 → 타입 불일치
  • if (a instanceof Integer) 조건문을 사용해도 해결되지 않음
enum Operator {
    ADD('+', (a, b) -> a.doubleValue() + b.doubleValue()),
    ...
    
    private final Operate<?> op;
    
    Operator(char symbol, Operate<?> op){
        this.symbol = symbol;
        this.op = op;
    }
}
@FunctionalInterface
public interface Operate<T extends Number> {
    T apply(T a, T b) throws Exception;
}
public <T extends Number> T invoke(T a, T b) {
    Number result = op.apply(a, b); // ❌ 여기서 컴파일 에러 발생
    ...
}

 

 

에러 메시지

  필요한 타입 제공된 타입
a capture of ? T
b capture of ? T

 

 

실행 시

java: incompatible types: T cannot be converted to capture#1 of ?


해결 방법

  • 타입을 상위 클래스 Number로 고정
    • Integer, Double 등 Number의 모든 하위 타입을 처리할 수 있다.
    • invoke 메서드에서는 런타임 타입에 따라 결과를 가공해 반환하면 된다.
private final Operate<Number> op;
public <T extends Number> T invoke(T a, T b) throws Exception {
    Number result;

    if(a instanceof Integer){
        result = op.apply(a, b).intValue();
    } else if(a instanceof Double){
        result = op.apply(a, b).doubleValue();
    } else {
        throw new IllegalArgumentException("정수나 실수 타입이 아닙니다.");
    }

    @SuppressWarnings("unchecked")
    T castedResult = (T) result;

    return castedResult;
}

배운 점

  • Java 제네릭에서 ?는 읽기 전용, 구체적인 타입이 필요할 때는 명확한 타입 지정이 필요하다.
  • enum은 타입 파라미터를 사용할 수 없으므로, 타입 유연성이 제한된다.
  • 실용적인 해결책으로 상위 타입 고정 + 런타임 처리 전략을 사용할 수 있다.

여담 .

 

요구사항을 맞추기 위해 제네릭을 사용했지만, (과제 키워드: 제네릭)

요구사항이 없었다면 굳이 제네릭을 사용하지 않고, Number 타입을 사용했을 것 같다. 😅