Generics는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크를 해주는 기능입니다.
장점으로는, 컴파일 시에 체크하기 때문에, 문법적인 오류를 바로 확인할 수 있고, 타입의 안정성을 높일 수 있습니다.
또한, 다룰(사용할) 객체 타입을 미리 명시함으로써, 형변환의 번거로움을 줄여줍니다.
지네릭는 아래와 같이 선언되어있습니다.
지네릭을 사용하지 않는 객체의 타입은 아래와 같습니다.
class Box {
Object item;
public Object getItem() {
return item;
}
public void setItem(Object item) {
this.item = item;
}
}
Box<T> 으로 지네릭클래스를 설정할 수 있습니다. T는 타입 변수를 뜻하며, 원하는 타입을 적용할 수 있습니다.
ArrayList<E> 의 경우에는 E = Element(요소)를 뜻하며, Map<K,V> 같은 경우에는 K=key , V=Value 를 뜻합니다.
( 기호의 종류만 다르고 참조형 타입을 사용한다는 의미는 같습니다. )
기본적으로 T , E , K , V 를 사용해도 상관없으나, 상황에 맞는 의미있는 타입을 작성해주는 것이 효율적으로 사용하는 방법입니다.
지네릭 타입을 이용해서 설정하면 아래와 같습니다.
String 타입만 사용할 수 있는 Box 에 set 을 이용해서 값을 설정해보면, String 이외의 타입은 에러가 발생하는 것을 볼 수 있습니다.
class Box<String> {
String item;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
...
Box<String> box = new Box<>();
box.setItem(new Object()); // 타입오류로 에러발생
box.setItem("박스셋팅");
}
지네릭스는 한계와 제한을 가지고 있습니다.
지네릭스는 static 멤버의 타입변수는 사용할 수 없습니다.
이유는 static은 모든 객체에 대해 동일하게 작동해야하므로, 멤버는 인스턴스변수를 참조하는 것은 불가능하기 때문입니다.
추가적으로, new 연산자 때문에 지네릭배열을 생성할 수 없습니다.
지네릭 클래스의 객체 생성은 타입이 같아야 가능합니다.
Box<Apple> appleBox = new Box<Apple>; // 가능
Box<Apple> appleBox = new Box<>; // 가능 (생략O)
Box<Apple> appleBox = new Box<peach>; // 에러 (타입불일치)
타입 문자로 사용할 타입을 명시하면 한 종류의 타입만 저장할 수 있지만, 모든 종류의 타입을 지정할 수 있는 문제가 있다.
FruitBox<Toy> fruitBox = new FruitBox<Toy>();
fruitBox.add(new Toy()); // 과일 상자에 장난감을 담을 수 있다.
이를 해결하기 위해서는 extends 를 이용해 특정 타입의 자식들만 대입할 수 있도록 한다.
class FruitBox<T extends Fruit> {...} // Fruit 의 자식만 담을 수 있다.
Fruit 뿐만 아니라 추가적인 인터페이스를 구현해야 한다면 아래와 같이 & 를 사용해 추가할 수 있다.
class FruitBox<T extends Fruit & Eatable> {...} // Fruit 의 자식과 Eatable 를 구현한 클래스를 담을 수 있다.
일반 클래스에서는 static 을 사용해서 매개변수로 지네릭을 사용할 수 있습니다.
class Juicer {
static Juice makeJuice(FruitBox<Fruit> box) { }
위와 같이 매개변수에 Fruit 로 명시해주면, 다른 FruitBox<Apple> 은 사용하지 못합니다.
아래처럼 오버로딩으로 처리할 수도 없습니다. 지네릭은 타입이 다른 것만으로는 오버로딩이 성립되지 않습니다.
class Juicer {
static Juice makeJuice(FruitBox<Fruit> box) { }
static Juice makeJuice(FruitBox<apple> box) { } // 에러 발생
이를 해결하기 위해서는 와일드 카드를 사용해야 합니다.
와일드 카드는 기호 "?" 표시로 표현합니다.
<?> | 제한 없음. <? extends Object> 와 동일하다 |
<? extends T> | T와 그 자식들만 가능 |
<? super T> | T와 그 부모들만 가능 |
와일드 카드를 사용하면 아래와 같이 변경할 수 있습니다.
class Juicer {
static Juice makeJuice(FruitBox<? extends Fruit> box) { }
참고 : 자바의 정석 3판
'Language > JAVA' 카테고리의 다른 글
람다식과 함수형 인터페이스 (0) | 2023.02.13 |
---|---|
쓰레드 동기화(Synchronization) (0) | 2023.02.13 |
Thread.sleep() 과 interrupted() (0) | 2023.02.12 |
쓰레드(Thread) 는 무엇일까? (0) | 2023.02.12 |
열거형(Enum) 을 알아보자 (0) | 2023.02.12 |
댓글