본문 바로가기

이슈

제네릭에 extends Number를 해도 사칙연산이 안되는 이유

과제를 수행하다가 제네릭에서 타입에 extends를 걸 수 있다는 사실을 알았습니다.

그래서 이전에 제네릭 타입T에 사칙연산을 해줄 수 없어서 형변환을 아래와 같은 방식으로 만들어 주었는데

double number1 = Double.parseDouble(positiveNumber1.toString());

아그럼이제 그럴 필요 없겠다! 생각을했습니다.

 

하지만 여전히 "연자사 '+' 를 "T","T"에 적용할 수 없습니다. 라는 에러가 발생하였고, 

엥? 똑같이 안되네? 하고 왜 안되는건지 찾아봤습니다. 

 

일단

<T extends Number>

의 진짜 의미는 T는 Number의 하위 타입이다. 

즉 T는 아래 중 하나 일 수 있습니다 :

Integer
Double
Long
BigDecimal
AtomicInteger
Byte
Short
...

 

하지만! 이 타입들은 공통으로 가진 연산 메서드가 없습니다.

*Number에는 +, -, , / 같은 연산이 정의되어 있지 않다.

즉 Java입장에서 T는 BigDecimal 일 수도, Integer , AtomicInteger  일수도 있는것입니다.

이 타입들은  연산 규칙이 다 다르기 때문에 java가 

positiveNumber1 + positiveNumber2 같은 코드를 허용하지 않는 것입니다.

 

그럼 왜 extends Number를 사용하는가?

"이 T는 숫자이다" 라는 것을 컴파일러에게 증명하기 위해서인데.

 

기존에 형변환을 조금 복잡한 방식으로 해주었는데.지금 코드를 보면 

Double.parseDouble(positiveNumber1.toString())
//Double 객체를 불러서
//그안에 있는 형변환 메서드 호출
//그리고 positiveNumber1 의 타입을 모르니 String으로 변환

이런식으로 코드가 짜여져있다.

하지만 이제는 Number의 하위 타입이란 것을 Java가 알았으니,

double number1 = positiveNumber1.doubleValue();

같은 Number 내장 함수를 사용 할 수있는것이다.

public class Calculator <T extends Number> {

    private ArrayList<T> calculateResult = new ArrayList<>();

    public double CalculateNumber(T positiveNumber1, T positiveNumber2 , OperatorType operator) {
        double number1 = positiveNumber1.doubleValue();
        double number2 = positiveNumber2.doubleValue();

        return switch (operator) {
            case OperatorType.PLUS ->  number1 + number2;
            case OperatorType.MINUS -> number1 - number2;
            case OperatorType.MULTIPLY ->  number1 * number2;
            case OperatorType.DIVIDE -> {
                if (number2 == 0) {
                    throw new ArithmeticException("0으로는 나눌 수 없습니다.");
                }
                yield number1 / number2;
            }
        };
    }

 

그리고 extends Number가 없다면...

Calculator c = new Calculator();  // raw type
c.CalculateNumber("hello", new Dog(), PLUS);

이런 끔찍한...코드도..컴파일러 단계에서 오류를 잡아주지 못한다...

그래서 제네릭의 진짜 목적은 "이 계산기는 여러 타입을 받을 수 있지만 그 타입들은 숫자만 다룬다" 라는 보증서? 계약서? 를 작성하는것과 같다고 생각합니다.