1. 제네릭이란 무엇인가?
구현 시에 클래스 내부에서 타입을 지정하는 것이 아니라, 일반화 해두고 선언시에 개발자가 타입을 지정하여 사용하는 것.
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
public static void main(String[] args) {
// Integer를 위한 Box 생성
Box<Integer> integerBox = new Box<>();
integerBox.setContent(10);
int intValue = integerBox.getContent();
System.out.println("정수 값: " + intValue);
// String을 위한 Box 생성
Box<String> stringBox = new Box<>();
stringBox.setContent("안녕, 제네릭!");
String stringValue = stringBox.getContent();
System.out.println("문자열 값: " + stringValue);
}
}
Box<T> 의 'T' 처럼 일반화된 타입으로 정의함
구현 시에, 명시적으로 구체적인 타입(Integer, String)을 지정함으로써 다용도로 사용할 수가 있게된다.
2. 왜 제네릭을 사용하고 이점이 무엇인가?
- 하나의 코드 ex) Box <T> 클래스처럼 클래스, 인터페이스, 메소드를 정의할 때 타입 매개변수를 사용하고 이를 구현시에 Integer, String 등 다양한 타입의 객체들을 처리할 수 있게 된다 -> 코드의 재사용성과 유연성이 높아짐
- 컴파일 시에 타입 검사를 해서, 런타임에 타입으로 인해 오류가 발생하는 것을 방지함
3. Collection과 Generic
컬렉션에서는 type에 관계 없이 제공해야 하는 함수들이 있다. add, get... 등
이를 제네릭이라는 개념을 통해 해결하는 것이다.
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
public void add(E e) {...}
public E get(int index) {...}
}
- ArrayList<E>
- ArrayList를 생성할 때 'E' 에 대한 실제 타입을 지정함
- add(E e)
- E는 매개변수로 전달된 객체의 유형
- E get(int index)
- E는 해당요소의 반환 유형
import java.util.ArrayList;
public class GenericExample {
public static void main(String[] args) {
// String 유형을 저장하는 ArrayList 생성
ArrayList<String> stringList = new ArrayList<>();
// add 메소드를 사용하여 요소 추가
stringList.add("Java");
stringList.add("Python");
stringList.add("C++");
// get 메소드를 사용하여 요소 가져오기
String language1 = stringList.get(0);
String language2 = stringList.get(1);
String language3 = stringList.get(2);
// 가져온 요소 출력
System.out.println("첫 번째 언어: " + language1);
System.out.println("두 번째 언어: " + language2);
System.out.println("세 번째 언어: " + language3);
}
}
-> 제네릭 덕분에 같은 기능을 수행하는 코드를 타입에 따라 중복으로 구현하지 않아도 됨
4. 와일드 카드 (?)
import java.util.ArrayList;
import java.util.List;
public class WildcardBoundsExample {
// 메서드 정의: 숫자 요소의 총합 계산 (상한 wildcard 사용)
public static double sumOfNumbersUpperBound(List<? extends Number> numbers) {
double sum = 0;
for (Number number : numbers) {
sum += number.doubleValue();
}
return sum;
}
public static void main(String[] args) {
// Double 리스트 생성
List<Double> doubleList = new ArrayList<>();
doubleList.add(1.5);
doubleList.add(2.5);
doubleList.add(3.5);
// 상한 wildcard를 사용하여 숫자 요소의 총합 계산
System.out.println("Double 리스트의 숫자 요소의 총합: " + sumOfNumbersUpperBound(doubleList));
}
}
- List<?>
- 모든 유형의 리스트 처리
- (상한 )List<? extends Number>
- Number 또는 Number 상속 받은 하위 클래스의 모든 숫자 유형 처리
- 반드시 Number 클래스와 관련되어 있는 상속한 클래스가 넘어와야 함
와일드 카드를 이용해 제네릭 타입의 경계를 정할 수 있다. -> 특정한 범위를 지정해서 더 정확하고 안전한 타입 변환을 한다.
'JAVA' 카테고리의 다른 글
[이펙티브 자바] 객체 생성과 파괴 (0) | 2024.07.13 |
---|---|
싱글톤 패턴과 프록시 패턴 (1) | 2024.05.01 |
IoC, DI, AOP 와 Spring (1) | 2024.05.01 |
자바의 신 인사이트 정리 (0) | 2024.03.21 |