CS 공부/Java

[기술 면접]Java Generic 이해하기1

sungwookujacheong 2025. 6. 2. 15:41
반응형

Q. 자바에서 제네릭(Generic)이 무엇인지 설명해 주세요.

A.자바의 제네릭은 클래스나 메서드를 만들 때, 미리 구체적인 데이터 타입을 정하지 않고

나중에 객체를 사용할 때 타을지정할 수 있도록 해 주는 기능입니다.
즉, “이 클래스는 나중에 어떤 타입을 쓸지는 실행 시점에 알려줄게요”라는 식으로 코드를 작성할 수 있게 해 주는 거죠.  

 

예를 들어, RPG 게임 속에서 ‘아이템 상자(ItemBox)’라는 객체를 만든다고 가정해 보겠습니다. 그런데 이 상자는 던전마다 담을 아이템 종류가 다를 수 있어요. 어떤 던전에서는 장비만 담아야 하고, 또 어떤 던전에서는 회복용 포션만 담아야 할 수도 있죠. 이럴 때 제네릭을 사용하면 다음처럼 타입 파라미터 T를 써서 아이템 상자를 일반화할 수 있습니다.

public class ItemBox<T> {
    private List<T> items = new ArrayList<>();

    public void addItem(T item) {
        items.add(item);
    }

    public T getItem(int idx) {
        return items.get(idx);
    }
}

 

 

위 코드에서 ItemBox<T>라고 하면, 실제로 상자를 쓸 때 T가 무엇인지 알려 주겠다는 뜻입니다.
만약 이 상자를 “이번에는 포션만 담는 상자”로 만들고 싶다면, 이렇게 작성합니다.

ItemBox<Potion> potionBox = new ItemBox<>();
potionBox.addItem(new Potion("체력 회복", 50));

 

이제 potionBox는 오직 Potion 객체만 저장할 수 있는 상자가 됩니다. 만약 실수로 ItemBox<Potion>에 Equipment 같은 다른 타입을 넣으려고 하면, 컴파일 단계에서 에러가 나서 “다른 타입은 넣을 수 없습니다”라고 알려줍니다.

자바 표준 컬렉션에도 똑같이 적용됩니다. 예를 들어 플레이어 목록과 몬스터 목록을 만들 때도 이렇게 쓰면,

List<Player> players = new ArrayList<>();
List<Monster> monsters = new ArrayList<>();

 

players 리스트에는 Player 객체만 넣을 수 있고, monsters 리스트에는 Monster 객체만 넣을 수 있게 컴파일러가 검사해 줍니다. 덕분에 값을 꺼낼 때마다 (Player)나 (Monster) 같은 캐스팅을 할 필요도 없어서 코드가 깔끔해집니다.

정리하면,

제네릭을 쓰면 같은 코드를 여러 타입에 재활용할 수 있고, 컴파일 시점에 타입을 꼭 맞춰 주기 때문에 타입 안전성(type safety)을 보장받을 수 있습니다.

 

 


 

Q. List<Object>와 List<?>의 차이는 무엇인가요?

A. 둘 다 “모든 타입이 올 수 있다”는 느낌이 들 수 있지만, 실제로는 용도가 다릅니다.


List<Object>

  • 말 그대로 Object 타입만 담을 수 있는 리스트입니다.
  • 따라서 list.add("문자열"), list.add(123) 등 모든 객체를 추가할 수 있습니다.
  • 단점은, 저장할 때는 자유롭지만 꺼낼 때는 항상 Object로 반환되므로, 다시 원래 타입으로 사용하려면 캐스팅이 필요합니다.
List<Object> list = new ArrayList<>();
list.add("안녕");
list.add(42);

Object o1 = list.get(0);
String s = (String) o1; // 캐스팅 필수

 

List<?> (비제한 와일드카드)

 

  • 말 그대로 “어떤 타입인지 모르는 상태”로 리스트를 참조만 하겠다는 의미입니다.
  • List<String>, List<Integer> 등 타입이 정해진 모든 리스트를 받을 수 있습니다.
  • 하지만 “어떤 타입인지” 컴파일러가 모르는 상태이므로, 요소를 추가하는(add) 동작은 불가능합니다. (null을 제외하고)
  • 대신 꺼내올 때는 항상 Object로 반환됩니다
public void printAll(List<?> list) {
    for (Object o : list) {
        System.out.println(o);
    }
    // list.add("테스트"); // 컴파일 에러! 어떤 타입인지 몰라서 추가 불가
}

 

 

요약하자면

  • List<Object>는 “이 리스트엔 실제로 모든 Object가 담긴다”라는 의미이므로 요소를 자유롭게 넣을 수 있지만, 꺼낼 때는 늘 캐스팅이 필요합니다.
  • List<?>는 “무슨 리스트든 받아서 참조만 하겠다”라는 의미로, 요소를 추가할 수는 없지만, 다양한 타입의 리스트를 한 메서드에서 같이 다룰 때 유용합니다.
반응형