[Java] 제네릭(Generic)이란?
java type
자바 제네릭
제네릭이란 무엇일까요? 자바에서 제네릭은 사용된 타입을 설명하는 특별한 방식으로, 코드 컴파일러가 타입 안전성을 보장하기 위해 사용할 수 있습니다. 다음과 같은 형태입니다.
1
2
3
4
5
public static void main(String[] args) {
List<String> lines = new ArrayList<>();
lines.add("Hello world!");
System.out.println(lines);
}
이 예제에서는 단순한 List가 아니라 String 타입의 객체만 다룰 수 있는 List라고 말하고 있습니다. 즉, 꺾쇠 괄호(<>) 안에 지정한 타입만 저장할 수 있다는 뜻입니다. 지정한 타입 이외의 다른 객체는 저장할 수 없습니다.
컴파일러는 이 코드에서 왼쪽에 List가 String 타입의 객체를 담는다고 명시되어 있다면, 오른쪽에서도 같은 타입의 객체를 담는 ArrayList를 생성하고자 한다는 것을 이해합니다. 즉, 왼쪽에 명시된 타입 정보를 바탕으로, 오른쪽의 타입을 추론하는 것입니다.
이러한 동작을 타입 추론(Type Inference) 이라고 부릅니다.
이제 직접 제네릭 클래스를 어떻게 작성할 수 있는지 예제를 통해 살펴보겠습니다.
예를 들어, 다음과 같은 클래스 계층 구조가 있다고 가정해 봅시다:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static abstract class Animal {
public abstract void voice();
}
public static class Cat extends Animal {
public void voice() {
System.out.println("Meow meow");
}
}
public static class Dog extends Animal {
public void voice() {
System.out.println("Woof woof");
}
}
여기서 동물들을 담을 수 있는 컨테이너 클래스를 만들고자 합니다. Animal 타입을 담는 일반적인 클래스를 만들 수도 있지만 고양이와 개를 함께 넣는 것은 좋지 않습니다. 서로 사이가 안 좋기 때문이죠. 게다가 누군가 이 컨테이너를 받았을 때 실수로 개 무리에 고양이를 넣을 수도 있고… 그 결과는 끔찍할 수 있습니다.
그래서 제네릭이 필요합니다.
예를 들어, 다음과 같이 제네릭 클래스를 만들 수 있습니다:
1
2
3
4
5
6
7
public static class Box<T> {
List<T> slots = new ArrayList<>();
public List<T> getSlots() {
return slots;
}
}
이 클래스는 T라는 제네릭 타입으로 정의된 객체들만 다룹니다. T는 일종의 타입의 별칭이며 클래스 이름 옆에 제네릭으로 선언되었기 때문에 클래스 내부 전체에서 사용할 수 있습니다.
예제:
1
2
3
4
5
public static void main(String[] args) {
Box<Cat> catBox = new Box<>();
Cat murzik = new Cat();
catBox.getSlots().add(murzik);
}
위 코드에서 Box
반대로 Box
제네릭 이름은 아무렇게나 지을 수 있지만 일반적으로는 다음과 같은 비공식적인 명명 규칙(Type Parameter Naming Conventions)을 따르는 것이 좋습니다:
- T — Type (가장 일반적인 타입 표시)
- E — Element (예: 리스트나 컬렉션의 요소 타입)
- K — Key (예: 맵의 키 타입)
- V — Value (예: 맵의 값 타입)
- N — Number (숫자 타입)
예시:
1
2
3
public class Box<T> { ... } // 일반 타입
public class Pair<K, V> { ... } // 키와 값
public class List<E> { ... } // 요소 타입
이러한 규칙은 필수가 아니라 관습(convention)이지만, 다른 개발자들과 협업할 때 코드 가독성을 높이는 데 큰 도움이 된다고 하네요.

