처음 자바를 배울 때는 제네릭이 이렇게 중요한 줄 몰랐는데 개발을 할 수록 제네릭 개념이 많이나와서 정리해보고자 한다. 해당 글은 인프런의 '김영한의 실전 자바 - 중급 2편'을 참고했다.
제네릭이 필요한 이유
왜 제네릭을 많이 사용할까? 사실 나는 개발할 때 많이 사용하지 않는다. 하지만 사용하고 있는 라이브러리 코드들을 확인해보면 T나 K가 사용되고 있는 코드들이 많았다. 많이 사용하는 이유 중 하나는 `코드의 재사용`이다.
코드의 재사용
제네릭을 사용하면 StringBox이든, IntegerBox이든 객체마다 새로운 클래스를 만들지 않고도 단 하나의 클래스만으로 여러 개의 클래스를 지원할 수 있게 된다.
public class GenericBox<T> {
private T value;
public void set(T value) {
this.value = value;
}
public T get() {
return value;
}
}
제네릭 클래스는 선언 시 매개변수의 구체적인 타입을 지정하지 않는다. '<>' 같은 다이아몬드 기호를 사용하여 일반적으로 T 라고 표기한다. 어느 객체든 올 수 있도록 문을 열어놓는 느낌이다.
제네릭은 클래스를 선언할 때 타입이 결정되지 않고, 클래스를 생성할 때 타입이 결정된다.
public static void main(String[] args) {
GenericBox<Integer> integerBox = new GenericBox<Integer>();
}
이렇게 생성하면 자바 컴파일러는 입력한 타입 정보를 기반으로 T를 Integer로 반영하여 해석하게 된다. 그러므로 `GenericBox` 객체를 생성하는 시점에 원하는 타입을 마음껏 지정할 수 있다.
제네릭 용어
제네릭에서 사용하는 용어에 대해 알아보자. 먼저 매개 변수와 인자의 개념을 짚으면 편하다.
void method(String param) //매개변수
void main() {
String arg = "hello";
method(arg) //인수 전달
}
우선 매개변수(Parameter)는 `String parma`을 말한다. 함수내에서 사용하고 있는 것이 매개변수이다. 인자(Argument)는 매개변수에 전달되는 값으로 코드에서 `arg`를 의미한다.
사실 나는 두 개의 차이를 잘 몰라 두 용어를 혼용해서 사용했었다. 보통 '함수에 매개변수를 전달해서~'라고 말했었는데 이는 명확한 표현이 아니었다. 이제부터 '함수에 인자를 전달해서 매개변수를 정한다'로 확실히 알고가자.
다시 제네릭 용어로 넘어와서, 제네릭도 메서드의 매개변수와 인자의 관계와 비슷하게 작동한다. 제네릭 클래스를 정의할 때 내부에서 사용할 타입을 미리 결정하는게 아니라 클래스를 실제 사용하는 생성 시점에 내부에서 사용할 타입을 결정한다.
메서드가 매개변수에 인자를 전달해서 사용할 값을 결정한다면, 제네릭 클래스는 타입 매개변수에 타입 인자를 전달해서 사용할 타입을 결정한다.
타입 매개변수: `GenericBox<T>` 에서 `T`
타입 인자:
- `GenericBox<Integer>` 에서 `Integer`
- `GenericBox<String>` 에서 `String
타입 매개변수는 제네릭 타입이나 메서드에서 사용하는 변수로, 실제 타입으로 대체된다. 참고로 제네릭을 사용할 때 T라고 많이 쓰지만 여기에 무엇을 쓰든 상관이 없다. Apple를 쓰든 hello를 쓰든 제네릭 변수로 인식된다. 하지만 다른 이름을 쓰면 다른 개발자에게 혼동을 줄 여지가 있으니 일반적인 관례를 따르도록 하자. 주로 사용하는 키워드는 아래와 같다.
예시
제네릭을 활용한 코드이다.
Pair.class
아래처럼 타입 매개변수를 한 번에 여러 개 선언할 수도 있다.
public class Pair<T, K> {
T first;
K second;
void setFirst(T first){
this.first = first;
}
void setSecond(K second){
this.second =second;
}
T getFirst(){
return this.first;
}
K getSecond(){
return this.second;
}
@Override
public String toString(){
return "Pair{"+
"first=" + first +
", second=" + second +
"}";
}
}
PairTest.class
public class PairTest {
public static void main(String[] args) {
Pair<Integer, String> pair1 = new Pair<>();
pair1.setFirst(1);
pair1.setSecond("data");
System.out.println(pair1.getFirst());
System.out.println(pair1.getSecond());
System.out.println("pair1 = " + pair1);
Pair<String, String> pair2 = new Pair<>();
pair2.setFirst("key");
pair2.setSecond("value");
System.out.println(pair2.getFirst());
System.out.println(pair2.getSecond());
System.out.println("pair2 = " + pair2);
}
}
출력 결과
'CS > 자바' 카테고리의 다른 글
[Java] String의 split() 메소드 뜯어보기 (0) | 2025.01.19 |
---|---|
자바 #6 - static과 final (1) | 2024.02.13 |
자바 #5 - 생성자와 접근 지정자 (1) | 2024.02.09 |
자바 #4 - 객체지향 언어의 특징 (0) | 2024.02.07 |
자바 #3 - 자바의 배열과 예외 처리 (1) | 2024.02.04 |