타입을 구체적으로 지정하는게 아니라 추후에 지정할 수 있도록 일반화 해놓는 것
작성한 코드 및 메서드 코드가 특정 데이터 타입에 얽메이지 않도록 해둔 것
class Basket<T> {
private T item;
public Basket(T item) {
this.item = item;
}
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
Basket<String> basket1 = new Basket<String>("기타줄");
Basket 클래스 내의 T를 String 으로 바꾼다는 뜻
위의 코드에서 T를 타입 매개변수라고 함
클래스 옆에 를 작성해줌으로써 클래스 내부에서 사용할 타입 매개변수를 선언할 수 있음.
타입 매개변수를 여러개 사용 해야 할 때
class Basket<K, V> { ... }
클래스 변수에는 타입 매개변수를 사용할 수 없다.
class Basket<T> {
private T item1; // O
static T item2; // X
}
클래스 변수에 타입 매개변수를 사용할 수 있다면 클래스 변수의 타입이 인스턴스 별로 달라지게 됨 따라서 static이 붙은 변수, 메서드 에는 타입 매개변수 사용 불가.
특정한 타입이 지정되지 않은 클래스 이므로 제네릭 클래스를 인스턴스화 할때는 의도하고자 하는 타입을 지정해 줘야함.
타입 매개변수에 치환될 타입으로 기본 타입을 지정할 수 없음 ex) int , double 같은 경우 Integer , Double 같은 래퍼 클래스를 활용해야함.
Basket<String> basket1 = new Basket<String>("Hello");
Basket<Integer> basket2 = new Basket<Integer>(10);
Basket<Double> basket3 = new Basket<Double>(3.14);
new Basket<>은 생략가능
Basket<String> basket1 = new Basket<>("Hello");
Basket<Integer> basket2 = new Basket<>(10);
Basket<Double> basket2 = new Basket<>(3.14);
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
class Basket<T> {
private T item;
public T getItem() {
return item;
}
public void setItem(T item) {
this.item = item;
}
}
class Main {
public static void main(String[] args) {
Basket<Flower> flowerBasket = new Basket<>();
flowerBasket.setItem(new Rose()); // 다형성 적용
flowerBasket.setItem(new RosePasta()); // 에러
}
}
Flower 클래스가 Rose클래스의 상위 클래스 이므로 flowerBasket.setItem(new Rose());가능 하지만 , RosePasta클래스와는 아무 관계가 없으므로 flower 타입으로 RosePasta의 객체를 참조 할수 없다.
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
class Basket<T extends Flower> {
private T item;
...
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<Rose> roseBasket = new Basket<>();
Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
}
}
위와같이 코드를 작성하면 Basket 클래스를 인스턴스화 할 때 타입으로 Flower 클래스의 하위 클래스만 지정 하도록 제한할 수 있음.
상속 받은 클래스 뿐만 아니라 인터페이스를 구현한 클래스만 타입으로 지정 할 수도 있음
이 경우에도 동일하게 extends 키워드를 사용함
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }
class Basket<T extends Plant> {
private T item;
...
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<Flower> flowerBasket = new Basket<>();
Basket<Rose> roseBasket = new Basket<>();
}
}
클래스를 상속 받으면서 동시에 인터페이스를 구현한 클래스만을 타입으로 지정 할 수도있다.
&를 사용해서 코드를 작성하는데 이 때 항상 인터페이스보다 클래스가 앞에와야한다.
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }
class Basket<T extends Flower & Plant> { // (1)
private T item;
...
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<Flower> flowerBasket = new Basket<>();
Basket<Rose> roseBasket = new Basket<>();
}
}