성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해주는 타입이다.
원래 클래스는 별도의 타입을 정해서 만든다.
//이게 원본
class Basket {
private String item;
Basket(String item) {
this.item = item;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
}
제네릭을 사용하면
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;
}
}
// 만약에 타입 매개변수를 여러개 사용하면
class Basket<K,V>{}
T : type, K : key, V : Value
//하지만 변수와 메소드에 static은 못쓴다.
제네릭 사용하면 클래스 하나로 모든 타입의 데이터를 저장할 수 있는 인스턴스를 만들 수 있다.
->객체를 만들려면
Basket<String> basket1 = new Basket<String>("미리미");
Basket<Integer> baslet2 = new Basket<Integer>();
// <T>를 String,Integer으로 하고 객체생성 이라는 뜻
다형성도 적용할수 있다.
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()); // 에러
}
}
------------------------------------------------
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<Rose> roseBasket = new Basket<>();
Basket<RosePasta> rosePastaBasket = new Basket<>();
}
}
인스턴스화 할때 타입을 하위 클래스만 지정하도록 제한 하는 방법
class Flower { ... }
class Rose extends Flower { ... }
class RosePasta { ... }
//1. Basket 클래스를 인스턴스화 할때 Flower 클래스의 하위 클래스만 지정 제한
class Basket<T extends Flower> {
private T item;
...
}
//2. 특정 인터페이스를 구현한 클래스만 타입으로 지정할 수 있도록 제한.
interface Plant { ... }
class Flower implements Plant { ... }
class Rose extends Flower implements Plant { ... }
class Basket<T extends Plant> {
private T item;
...
}
//3. 특정 클래스를 상속받으면서 동시에 특정 인터페이스를 구현한 클래스만 타입으로 제한할때
//&를 사용
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) {
// 1번 인스턴스화
Basket<Rose> roseBasket = new Basket<>();
Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
//2번 인스턴스화
Basket<Flower> flowerBasket = new Basket<>();
Basket<Rose> roseBasket = new Basket<>();
//3번 인스턴스화
Basket<Flower> flowerBasket = new Basket<>();
Basket<Rose> roseBasket = new Basket<>();
}
}
클래스 전체 말고, 클래스 내부의 특정 메소드만 제네릭으로 선언한것
class Basket{
public <T> void add(T element) {
...
}
}
단 알아야 할점
class Basket<T>{//1번 여기 매개변수 타입 T
publc <T> void add(T element){ 2번여기 매개변수 타입 T
}
}
---
이젠 메소드 타입 매개변수는 static 메소드에서도 선언 해서 사용할수 있다.
class Basket{
static <T> int setPrice(T element){
}
}
저 1번 2번은 서로 다른 별개의 것이다.
이름만 T라고 같지 서로 다른 매개변수 타입이다.
클래스명 옆에서 선언한 타입 매개변수는 클래스가 인스턴스화될 때 타입이 지정된다.
하지만 제네릭 메소드 타입 지정은 메소드가 호출 될때 된다.
Basket<String> basket = new Bakset<>();
basket.<Integer>add(10);
basket.add(10);//이렇게 타입 지정을 생략도 할수 있다.
length()와 같이 String 클래스 메소드는 사용못하지만
Object클래스 메소드는 사용할수 있다
class Basket {
public <T> void print(T item) {
System.out.println(item.length()); // 불가
System.out.println(item.equals("Kim coding")); // 가능
}
}
어떠한 타입으로든 대체될수 있는 타입 파라미터.
기호는 ?
<? extends T>
<? super T>
는 T와 T를 상속 받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정한다.
는 T와 T의 상위 클래스만 타입 파라미터로 받도록 한다.