제네릭 - Generic(1)
#Java
정리
제네릭이 필요한 이유
코드 재사용을 늘리기 위해 Object
와 다형성을 사용하면 타입 안전성이 떨어지는 문제가 발생한다.
- 각각의 타입별로
IntegerBox
,StringBox
와 같은 클래스를 모두 정의- 코드 재사용X
- 타입 안전성O
ObjectBox
를 사용해서 다형성으로 하나의 클래스만 정의- 코드 재사용O
- 타입 안전성X
제네릭 적용
제네릭을 사용하면 코드 재사용과 타입 안전성이라는 두 마리 토끼를 한 번에 잡을 수 있다.
예시
package generic.ex1;
public class GenericBox<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
- <>를 사용한 클래스를 제네릭 클래스라 한다.
- 이 기호(
<>
)를 보통 다이아몬드
- 이 기호(
- 제네릭 클래스를 사용할 때는
Integer
,String
같은 타입을 미리 결정하지 않는다. - 클래스명 오른쪽에
<T>
와 같이 선언하면 제네릭 클래스가 된다. T
를 타입 매개변수라고 한다.- 클래스 내부에
T
타입이 필요한 곳에T value
와 같이 타입 매개변수를 적어두면 된다.
생성 시점에 원하는 타입 지정
제네릭 클래스는 생성하는 시점에 <>
사이에 원하는 타입을 지정한다.
new GenericBox<Integer>()
이렇게 하면 앞서 정의한 GenericBox
의 T
가 다음과 같이 지정한 타입으로 변한 다음 생성된다.
원하는 모든 타입 사용 가능
제네릭 클래스를 사용하면 GenericBox
객체를 생성하는 시점에 원하는 타입을 마음껏 지정할 수 있다.
제네릭 컴파일 과정
제네릭을 도입한다고 해서 앞서 설명한 GenericBox<String>
, GenericBox<Integer>
와 같은 코드가 실제 만들어지는 것은 아니다. 대신에 자바 컴파일러가 우리가 입력한 타입 정보를 기반으로 이런 코드가 있다고 가정하고 컴파일 과정에 타입 정보를 반영한다. 이 과정에서 타입이 맞지 않으면 컴파일 오류가 발생한다.
타입 추론
GenericBox<Integer> integerBox2 = new GenericBox<>() // 타입 추론
자바는 왼쪽에 있는 변수를 선언할 때의 <Integer>
를 보고 오른쪽에 있는 객체를 생성할 때 필요한 타입 정보를 얻을 수 있다. 따라서 new GenericBox<>()
와 같이 타입 정보를 생략할 수 있다.
이렇게 자바가 스스로 타입 정보를 추론해서 개발자가 타입 정보를 생략할 수 있는 것을 타입 추론이라 한다.
참고로 타입 추론이 그냥 되는 것은 아니고, 자바 컴파일러가 타입을 추론할 수 있는 상황에만 가능하다.
제네릭 용어와 컨벤션
제네릭의 핵심은 사용할 타입을 미리 결정하지 않는다는 점이다. 생성 시점에 타입을 결정한다.
제네릭의 타입 매개변수와 타입 인자
정리하면 다음과 같다.
- 메서드는 매개변수에 인자를 전달해서 사용할 값을 결정한다.
- 제네릭 클래스는 타입 매개변수에 타입 인자를 전달해서 사용할 타입을 결정한다.
메서드에서 사용하는 용어를 그대로 가져다 사용하지만, 값이 아니라 타입을 결정하는 것이기 때문에 앞에 타입을 붙인다.
- 타입 매개변수:
GenericBox<T>
에서T
- 타입 인자:
GenericBox<Integer>
에서Integer
GenericBox<String>
에서String
제네릭 타입의 타입 매개변수 <T>
에 타입 인자를 전달해서 제네릭의 사용 타입을 결정한다.
- 제네릭 타입 (Generic Type)
- 클래스나 인터페이스를 정의할 때 타입 매개변수를 사용하는 것을 말한다.
- 제네릭 클래스, 제네릭 인터페이스를 모두 합쳐서 제네릭 타입이라 한다.
- 타입은 클래스, 인터페이스, 기본형(
int
등)을 모두 합쳐서 부르는 말이다.
- 타입은 클래스, 인터페이스, 기본형(
- 예:
class GenericBox<T> { private T t;}
에서GenericBox<T>
- 타입 매개변수 (Type Parameter)
- 제네릭 타입이나 메서드에서 사용되는 변수로, 실제 타입으로 대체된다.
- 예:
GenericBox<T>
에서의 T
- 타입 인자 (Type Argument)
- 제네릭 타입을 사용할 때 제공되는 실제 타입이다.
제네릭 명명 컨벤션
타입 매개변수는 일반적인 변수명처럼 소문자로 사용해도 문제는 없다. 하지만 일반적으로 대문자를 사용하고 용도에 맞는 단어의 첫 글자를 사용하는 관례를 따른다. 주로 사용하는 키워드는 다음과 같다.
E
- ElementK
- KeyN
- NumberT
- TypeV
- ValueS
,U
,V
etc. - 2nd, 3rd, 4th types
제네릭 타입에서는 여러 타입 매개변수를 선언할 수 있다. 만약 타입이 두 개면 T1, T2… 요런 식으로 붙인다.
타입 인자로 기본형은 사용할 수 없다
제네릭의 타입 인자로 기본형(int
, double
등)은 사용할 수 없다. 대신 래퍼 클래스를 사용하면 된다.
로 타입
GenericBox integerBox = new GenericBox();
제네릭 타입을 사용할 때는 항상 <>
를 사용해서 사용 시점에 원하는 타입을 지정해야 한다. 그런데 위과 같이 <>
을 지정하지 않을 수 있는데, 이런 것을 로 타입(raw type), 또는 원시 타입이라 한다.
원시 타입을 사용하면 내부의 타입 매개변수가 Object
로 사용된다고 이해하면 된다. 레거시 때문에 로 타입을 지원하는 것이다. (== 로 타입은 사용하지 말자). Object 타입을 쓸 거면 타입 인자로 Object를 직접 지정해주자.
예시
public class Box<T> {
private T value;
public void setValue(T value) {
this.value = value;
}
public T getValue() {
return value;
}
}
Box
제네릭 클래스에 각각의 타입에 맞는 동물을 보관하고 꺼낸다.Box<Dog> dogBox
:Dog
타입을 보관할 수 있다.Box<Cat> catBox
:Cat
타입을 보관할 수 있다.Box<Animal> animalBox
:Animal
타입을 보관할 수 있다.
- Dog과 Cat이 Animal의 하위 타입이므로,
Box<Animal>
에 Dog과 Cat을 set하고 get할 수 있다.
'Programming Language > Java' 카테고리의 다른 글
[Java] 29. 컬렉션- ArrayList, LinkedList, List (0) | 2025.01.19 |
---|---|
[Java] 28. 제네릭 - Generic(2) (0) | 2025.01.13 |
[Java] 26. 예외 처리 - 실전 (0) | 2025.01.13 |
[Java] 25. 예외 처리 - 이론 (0) | 2025.01.13 |
[Java] 24. 중첩 클래스, 내부 클래스(2) (0) | 2025.01.13 |