Files
java-examples/docs/Generic.md

149 lines
5.0 KiB
Markdown

# **자바 제너릭(Generic) 쉽게 배우기**
## **1. 제너릭이 뭐야?**
제너릭(Generic)은 **클래스나 메서드에서 사용할 데이터 타입을 미리 지정하지 않고, 나중에 정할 수 있게 해주는 기능**이다.
쉽게 말해 **"박스를 만들되, 안에 뭐가 들어갈지는 나중에 정하는 것"**과 같다.
예를 들어, `List`는 여러 종류의 데이터를 저장할 수 있다.
```java
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();
```
여기서 `List<String>`은 문자열만, `List<Integer>`는 정수만 저장할 수 있다.
이처럼 **제너릭을 사용하면 타입을 강제할 수 있어 코드의 안정성이 높아진다.**
---
## **2. 제너릭을 사용하지 않으면? (비교 예제)**
제너릭을 사용하지 않는 코드:
```java
List list = new ArrayList();
list.add("Hello");
list.add(123); // 문자열 리스트인데 숫자가 들어감
String str = (String) list.get(1); // 실행 시 오류 발생 가능!
```
위 코드에서는 `List`**어떤 타입의 데이터를 가질지 정해져 있지 않다.**
따라서 다른 타입의 데이터가 들어와도 **컴파일러가 오류를 잡아주지 못한다.**
---
## **3. 제너릭을 사용한 코드 (안전한 코드!)**
```java
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123); // 컴파일 오류 발생! (안전성 증가)
String str = list.get(0); // 타입 캐스팅 없이 사용 가능
```
**제너릭을 사용하면 타입을 제한할 수 있어 실수를 줄이고, 형 변환 없이 안전하게 데이터를 사용할 수 있다!**
---
## **4. 제너릭 클래스 만들기**
제너릭을 직접 만들어 보자!
```java
class Box<T> { // T는 타입 매개변수
private T item;
public void setItem(T item) {
this.item = item;
}
public T getItem() {
return item;
}
}
```
이제 `Box<T>`를 다양한 타입으로 사용할 수 있다.
```java
Box<String> strBox = new Box<>();
strBox.setItem("Hello");
System.out.println(strBox.getItem()); // Hello
Box<Integer> intBox = new Box<>();
intBox.setItem(100);
System.out.println(intBox.getItem()); // 100
```
**제너릭을 사용하면 같은 코드로 여러 타입을 지원할 수 있어 코드의 재사용성이 높아진다!**
---
## **5. 제너릭 메서드 만들기**
제너릭은 클래스뿐만 아니라 **메서드에서도 사용할 수 있다.**
```java
class Util {
public static <T> void printItem(T item) {
System.out.println(item);
}
}
Util.printItem("Hello"); // Hello
Util.printItem(123); // 123
Util.printItem(3.14); // 3.14
```
**제너릭 메서드를 사용하면 여러 타입을 지원하는 함수를 쉽게 만들 수 있다!**
---
## **6. 제너릭 타입 제한하기 (extends 사용)**
어떤 타입이든 받을 수 있는 것도 좋지만, **특정 타입만 허용하고 싶을 때**가 있다.
이럴 때 `extends` 키워드를 사용해 제한할 수 있다.
```java
class NumberBox<T extends Number> { // Number 또는 그 자식 타입만 가능
private T num;
public NumberBox(T num) {
this.num = num;
}
public double getDoubleValue() {
return num.doubleValue();
}
}
```
사용 예시:
```java
NumberBox<Integer> intBox = new NumberBox<>(10);
System.out.println(intBox.getDoubleValue()); // 10.0
NumberBox<Double> doubleBox = new NumberBox<>(5.5);
System.out.println(doubleBox.getDoubleValue()); // 5.5
// NumberBox<String> strBox = new NumberBox<>("Hello"); // 오류 발생!
```
**제너릭에 `extends`를 사용하면 특정 타입만 허용할 수 있어 더 안전한 코드 작성이 가능하다!**
---
## **7. 와일드카드 (`?`) 활용하기**
제너릭을 사용하다 보면 **다양한 타입을 받아야 하지만, 타입을 정확히 모를 때**가 있다.
이럴 때 **와일드카드 (`?`)** 를 사용할 수 있다.
```java
public static void printList(List<?> list) {
for (Object obj : list) {
System.out.println(obj);
}
}
```
사용 예시:
```java
List<String> strList = Arrays.asList("A", "B", "C");
List<Integer> intList = Arrays.asList(1, 2, 3);
printList(strList); // A, B, C
printList(intList); // 1, 2, 3
```
**`?`를 사용하면 어떤 타입이든 받을 수 있어 유연한 코드 작성이 가능하다!**
---
## **8. 정리**
**제너릭을 사용하면 코드의 타입 안정성이 증가하고, 불필요한 형 변환을 줄일 수 있다!**
**제너릭 클래스(`Box<T>`)를 사용하면 여러 타입을 지원하는 재사용 가능한 클래스를 만들 수 있다!**
**제너릭 메서드(`printItem<T>(T item)`)를 사용하면 다양한 타입을 처리하는 메서드를 쉽게 작성할 수 있다!**
**`extends`를 사용하면 특정 타입만 허용할 수 있다!**
**`?`(와일드카드)를 사용하면 유연한 코드 작성이 가능하다!**
자바 제너릭을 활용하면 **더 안전하고 재사용 가능한 코드**를 작성할 수 있다!