1.1 제네릭의 개념 및 필요성
제네릭이란 무엇인가?
제네릭(Generic)은 클래스나 메서드를 다양한 타입으로 재사용할 수 있도록 도와주는 기능이다.
쉽게 말해, 데이터를 담을 때 "어떤 타입이 들어올지 미리 지정하지 않고, 사용자가 필요에 따라 지정하게 하는" 방식을 말한다.
Java 5부터 Generic이라는 타입이 새로 추가되었다.
제네릭은 왜 필요할까?
// 타입을 지정하지 않는 경우
List list = new ArrayList();
list.add("Hello");
list.add(123);
// 다양한 타입이 들어갈 수 있음.
// 제네릭을 사용하는 경우
List<String> list = new ArrayList<>();
list.add("Hello");
// list.add(123);
// 타입 불일치로 컴파일 오류가 발생한다.
자바 5 이전에는 컬렉션 같은 클래스에 다양한 타입의 객체를 넣을 수 있었지만, 이러한 방식은 타입 오류가 런타임에 발생하는 문제가 있었다. 제네릭은 컴파일 시점에 타입 오류를 잡아내기 위해 도입되었다.
- 타입 안전성: 컴파일러가 타입을 검증하므로 런타임 오류가 줄어든다.
- 코드 재사용성: 다양한 타입에 대해 하나의 클래스나 메서드를 재사용할 수 있다.
1.2 제네릭 타입의 사용법
- 제네릭 클래스와 메서드의 정의 및 예시
class Box<T> {
private T content;
public T getContent() { return content; }
public void setContent(T content) { this.content = content; }
}
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
System.out.println(stringBox.getContent());
- 제네릭 타입의 경계(bound) 설정 방법 (<T extends Class>)
class NumberBox<T extends Number> {
private T number;
public NumberBox(T number) { this.number = number; }
public double getDoubleValue() { return number.doubleValue(); }
}
NumberBox<Integer> intBox = new NumberBox<>(123);
System.out.println(intBox.getDoubleValue());
T extends Number는 제네릭 타입 T가 Number 타입이나 그 하위 클래스만 허용하도록 제한한다.
1.3 제네릭 관련 면접 질문
- 제네릭 타입 사용 시 컴파일러의 역할은 무엇인가요?
자바 컴파일러는 제네릭 타입을 타입 소거(type erasure)를 통해 처리한다. 즉, 제네릭 타입은 컴파일 후 타입 정보를 제거하여, 실제로는 Object 타입으로 변환된다. 이렇게 변환되는 이유는 역호환성을 보장하고 제네릭 타입의 이점을 유지하기 위함이다.
역호환성을 유지한다는 것은 제네릭을 사용하지 않는 이전의 자바 코드가 여전히 작동할 수 있도록 한다는 것이다.
그래서 제네릭을 사용할 때는 컴파일 시점에 타입이 안전하게 검사되지만, 런타임에는 이 타입 정보가 없어져서 컴파일러가 자동으로 캐스팅을 추가해준다.
- 제네릭 타입의 제한사항에 대해서 말해보세요.
배열 생성 불가: 제네릭 배열을 직접 생성할 수 없다.
// 오류 발생
List<Integer>[] intLists = new ArrayList<Integer>[10];
기본 타입 사용 불가: int, double 같은 기본 타입을 사용할 수 없고, 대신 Integer, Double 같은 래퍼 클래스를 사용해야 한다.
타입 검사: 런타임에 타입 검사를 할 수 없으므로, instanceof 연산자 사용에 제한이 있다.
1.4 예제 코드
class SumCalculator<T extends Number> {
private T num1;
private T num2;
public SumCalculator(T num1, T num2) {
this.num1 = num1;
this.num2 = num2;
}
public double calculateSum() {
return num1.doubleValue() + num2.doubleValue();
}
}
SumCalculator<Integer> intSum = new SumCalculator<>(10, 20);
System.out.println("Integer Sum: " + intSum.calculateSum());
SumCalculator<Double> doubleSum = new SumCalculator<>(10.5, 20.3);
System.out.println("Double Sum: " + doubleSum.calculateSum());
- T extends Number를 사용하여 숫자 타입만 허용
- calculateSum 메서드는 doubleValue() 메서드를 사용해 제네릭 타입의 숫자 값을 더할 수 있게 함.
'프로그래밍 언어 > Java' 카테고리의 다른 글
자바 람다와 스트림 – 효율적인 코드 작성 (1) | 2024.11.09 |
---|---|
자바 컬렉션 프레임워크 – 자바에서 데이터를 다루는 방법 (0) | 2024.11.09 |
Java 프로그래밍 초급(5) - 컬렉션 프레임워크 : List (0) | 2022.01.26 |
Java 프로그래밍 초급(4) - 컬렉션 프레임워크 : 개념, 제네릭 (0) | 2022.01.26 |
Java 프로그래밍 초급(3) - 객체지향 고급(오버라이딩, 다형성, 패키지) (0) | 2022.01.26 |