제네릭의 주요 개념
- 타입 매개변수: 제네릭은 타입을 매개변수처럼 사용할 수 있게 해줍니다. 클래스나 메서드를 정의할 때 타입을 지정하지 않고, 실제 사용할 때 타입을 지정합니다.
- 타입 안전성: 제네릭을 사용하면 컴파일 타임에 타입 오류를 방지할 수 있습니다. 이는 런타임에 발생할 수 있는 타입 오류를 사전에 방지하는 데 도움이 됩니다.
- 코드 재사용성: 제네릭을 사용하면 동일한 코드를 다양한 데이터 타입으로 재사용할 수 있습니다. 별도의 타입에 대해 각각의 클래스를 작성할 필요가 없습니다.
1. 제네릭 클래스
제네릭 클래스는 클래스 정의 시점에 타입을 지정하지 않고, 클래스 사용 시점에 타입을 지정할 수 있습니다.
public class Box<T> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return this.item;
}
}
위 예제에서 Box 클래스는 타입 매개변수 T를 사용합니다. T는 나중에 Box 객체를 생성할 때 지정됩니다.
public class Main {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
System.out.println(stringBox.getItem());
Box<Integer> intBox = new Box<>();
intBox.setItem(123);
System.out.println(intBox.getItem());
}
}
위 코드에서 stringBox는 String 타입을, intBox는 Integer 타입을 저장할 수 있습니다.
2. 제네릭 메서드
제네릭 메서드는 메서드 정의 시점에 타입을 지정하지 않고, 메서드 호출 시점에 타입을 지정할 수 있습니다.
public class Util {
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.print(element + " ");
}
System.out.println();
}
}
위 예제에서 printArray 메서드는 타입 매개변수 T를 사용합니다.
public class Main {
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"A", "B", "C"};
Util.printArray(intArray);
Util.printArray(stringArray);
}
}
위 코드에서 printArray 메서드는 Integer 배열과 String 배열을 처리할 수 있습니다.
3. 제네릭의 제한
제네릭 타입에는 상한 경계를 지정하여 특정 타입의 하위 클래스들만 허용할 수 있습니다.
public class Box<T extends Number> {
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return this.item;
}
}
------------------------------------
public class Main {
public static void main(String[] args) {
Box<Integer> intBox = new Box<>();
intBox.setItem(123);
System.out.println(intBox.getItem());
Box<Double> doubleBox = new Box<>();
doubleBox.setItem(45.67);
System.out.println(doubleBox.getItem());
// Box<String> stringBox = new Box<>(); // 오류 발생
// Error : type argument java.lang.String is not within bounds of type-variable T
// 해석 : 유형 인수 java.lang.String이 유형 변수 T의 범위 내에 있지 않습니다.
}
}
위 예제에서 Box 클래스는 Number 타입과 그 하위 타입만을 허용합니다. 따라서 Box<Integer>와 Box<Double>는 가능하지만, Box<String>은 불가능합니다.
4. 제네릭을 사용한 간단한 예제
제네릭 클래스 사용 예제
// 제네릭 클래스 정의
public class Box<T> {
private T item;
// 아이템 설정 메서드
public void setItem(T item) {
this.item = item;
}
// 아이템 반환 메서드
public T getItem() {
return this.item;
}
}
------------------------------------------------------------
public class Main {
public static void main(String[] args) {
GenericList<String> stringList = new GenericList<>();
stringList.add("Hello");
stringList.add("World");
System.out.println("첫 번째 요소: " + stringList.get(0));
System.out.println("리스트 크기: " + stringList.size());
GenericList<Integer> intList = new GenericList<>();
intList.add(10);
intList.add(20);
System.out.println("첫 번째 요소: " + intList.get(0));
System.out.println("리스트 크기: " + intList.size());
}
}
위 예제에서 GenericList 클래스는 제네릭 타입 T를 사용하여 다양한 타입의 리스트를 만들 수 있습니다.
정리
- 제네릭 클래스: 타입 매개변수를 사용하여 다양한 데이터 타입을 처리할 수 있는 클래스를 정의합니다. 실제 사용할 때 원하는 타입을 지정합니다.
- 제네릭 메서드: 메서드에서도 제네릭을 사용하여 다양한 타입의 데이터를 처리할 수 있습니다.
이와 같은 방식으로 제네릭을 사용하면 코드의 재사용성을 높이고, 타입 오류를 컴파일 타임에 방지할 수 있습니다.
'JAVA' 카테고리의 다른 글
Iterator: 컬렉션을 안전하게 순회하기 (0) | 2024.08.05 |
---|---|
쓰레드(Thread)란? (0) | 2024.07.25 |
예외처리(Exception) (0) | 2024.07.24 |
객체지향(추상 클래스 (Abstract Class) ,인터페이스 (Interface)) (0) | 2024.07.24 |
객체지향(오버로딩 (Overloading), 오버라이딩 (Overriding)) (0) | 2024.07.24 |