Welcome! Everything is fine.

[TIL] 계산기 과제 해설, 와일드카드, 타입 이레이저 본문

TIL

[TIL] 계산기 과제 해설, 와일드카드, 타입 이레이저

개발곰발 2025. 1. 10.
728x90

계산기 과제 해설

과제 제출 마감 직후, 바로 튜터님의 해설 세션이 시작되었다. 해설을 들으며 내가 빼먹은 부분이나 몰랐던 부분을 알게 되었다.

 

✔️ null을 조심하자
보통 문자열이 같은지 확인하기 위해 equals() 메서드를 쓸 때, 다음과 같이 사용해왔다.

input.equals("exit");

하지만 확실히 null이 될 수 없는 것을 앞에 두는 것이 좋다고 한다.

“exit”.equals(input);

 

✔️ 요구사항은 꼼꼼히
예외처리를 할 때, 여러 상황에서 살펴봤지만 정작 양의 정수로 제한하는 예외 처리를 빼먹었다.
요구사항을 더 꼼꼼히 살피는 습관을 들이자.

if (num1 < 0) {
   throw new IllegalStateException("양의 정수만 입력할 수 있습니다.");
}

 

✔️ 타입 매개변수 제한이 중요!
Lv.3에서 사용된 제네릭은 사용해봤다는 것이 중요하다고 하셨다. 특히 <T extends Number> 와 같이 타입 매개변수 제한을 통해 숫자만 받도록 하는 것이 중요하다.

튜터님께서 올려주신 코드를 뜯어보며 부족한 부분을 더 채워봐야할 것 같다.

 

✅ 자바 강의 듣기

와일드카드

와일드카드란 제네릭을 쉽게 쓸 수 있도록 도와주는 도구로, 타입 인자가 정해진 제네릭 타입을 전달 받아서 활용할 때 사용한다. 다음과 같이 <> 안에 ?를 넣어 사용한다.

static void printWildcardV1(Box<?> box) {
    System.out.println("? = " + box.get());
}
  • ?의 뜻은 모든 타입을 다 받을 수 있다는 뜻이다.
  • 매개변수로 제네릭 타입을 받을 수 있는 일반적인 메서드이다.
  • 더 단순하기 때문에 사용이 권장된다.

와일드카드에도 다음과 같이 extends 키워드를 이용해 상한 제한을 둘 수 있다. Box<? extends Animal>과 같이 쓴다면, Animal과 그 하위 타입만 입력받을 수 있다.

static void printWildcardV2(Box<? extends Animal> box) {
    Animal animal = box.get();
    System.out.println("이름 = " + animal.getName());
}

또한 와일드카드는 super 키워드를 이용해 하한도 지정할 수 있다. Box<? super Animal> 과 같이 쓴다면, Animal과 그 상위 타입만 입력받을 수 있다. 즉, 아래 예시에서는 Animal과 Object 타입만 허용된다.

static void writeBox(Box<? super Animal> box) {
    box.set(new Dog("망망이", 100));
}

타입 이레이저

타입 이레이저란 자바 컴파일 단계에서만 제네릭이 사용되고, 컴파일 이후에는 제네릭 정보가 삭제되는 것을 말한다.

예를 들어 다음과 같이 제네릭 타입을 선언한 후에 Integer 타입 인자를 전달했다면,

public class Box<T> {

    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

 

자바 컴파일러는 컴파일 시점에 다음과 같이 이해한다.

public class Box<Integer> {

    private Integer value;

    public void set(Integer value) {
        this.value = value;
    }

    public Integer get() {
        return value;
    }
}

 

그리고나서 컴파일이 끝나면 제네릭 관련 정보를 모두 삭제해서 .class 파일에는 다음과 같은 정보가 생성된다.

public class Box {

    private Object value;

    public void set(Object value) {
        this.value = value;
    }

    public Object get() {
        return value;
    }
}

 

값을 꺼낼 때도 자바 컴파일러가 Integer로 캐스팅하는 코드를 추가해주기 때문에 문제가 발생하지 않는다.

void main() {
    GenericBox box = new GenericBox();
    box.set(10);
    Integer result = (Integer) box.get(); // 컴파일러가 캐스팅 추가
}

 

하지만, 이런 타입 이레이저 방식으로 인해 다음과 같은 코드를 작성할 수 없다. 여기서 T는 모두 런타임에 Object로 바뀌기 때문에, instanceof는 항상 Object와 비교하게 되어서 소용이 없어진다. new T() 또한 항상 new Object가 된다.

class EraserBox<T> {
    public boolean instanceCheck(Object param) {
        return param instanceof T; // 오류
    }
    public void create() {
       return new T(); // 오류
    }
}