제네릭
지금까지 클래스는 필드에서 정해진 타입만 담을수 있었음
class BasketString { private String item; ... }
class BasketInteger { private int item; ... }
class BasketChar { private char item; ... }
class BasketDouble { private double item; ... }
이런식으로 타입마다 클래스를 만들어야 함
안에 있는 요소의 타입을 만드는 시점에 동적으로 타입? 지정할수 있음
타입을 약간 미지로 남겨놓는 형태 -> ex) <T>
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<Integer> basket1 = new Basket<>(1); // 뒤에 생략 가능
Basket<Boolean> basket1 = new Basket<>(true);
맨위에 라인은 “Basket 클래스 내의 T를 String으로 바꿔라.” 라는 의미를 가지고 있음
제네릭은 제약조건이 있음
타입 매게변수에 원시자료형 사용 불가능 참조자료형만 가능함
참조자료형 -- 객체, String , Array, Wrapper클래스( Byte, Short, Integer, Long, Float, Double, Character, Boolean )
- 참조 자료형은 기본 자료형과 달리 메서드를 가질 수 있다.
- 참조 자료형의 기본값은 null이다
그래서 <int> 가 아닌 <Integer> 가능
랩핑클래스가 필요한 이유는 제네릭 때문에!!
원래 int 는 null 값이 들어올수 없음 원시 자료형 이기 떄문에
하지만 제네릭에는 Integer 참조자료형만 들어올수 있기에 null 값 들어올수 있음
즉 제네릭이란?
타입을 구체적으로 지정하는 것이 아니라, 추후에 지정할 수 있도록 일반화해 두는 것을 의미
작성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해 둔 것을 의미
제네릭 클래스
제네릭이 사용된 클래스를 제네릭 클래스라고 함
하나만 쓸때는 보통 T 만 씀 (Type)
두개 세개는 보통 < T , K , V > Type, Key, Value
그외 E - Element , N - Number, R - Result
제네릭 클래스를 정의할 때 주의할 점
클래스 변수에는 타입 매개변수를 사용할 수 없습니다.
class Basket<T> {
private T item1; // O
static T item2; // X
}
static 못 붙음 -> 상태 공유해야 하는데 제네릭은 상태 공유가 불가능하기에 사용할수 없음
형변환 가능~~
제한된 제네릭 클래스
타입을 지정하는 데에 있어 제한이 없
class ObjectBasket {
private Object item;
public Object getItem() {
return item;
}
public void setItem(Object item) {
this.item = item;
}
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<String> genericBasket = new Basket<>();
ObjectBasket objectBasket = new ObjectBasket();
objectBasket.setItem("String 어쩌고 저쩌고");
objectBasket.getItem(); //toUpperCase() 못쑴
genericBasket.getItem().toUpperCase(); // -> 사용가능
//스트링 관련된 모든 메서드 사용가능
Basket<Integer> integerBasket = new Basket<>();
// integerBasket.getItem(). -> integer 관련된 메서드? 사용가능
}
}
그러나, 타입 매개변수를 선언할 때 아래와 같이 코드를 작성해 주면 Basket 클래스를 인스턴스화할 때 타입으로 Flower 클래스의 하위 클래스만 지정하도록 제한됨
class Flower {
public void bloom(){
System.out.plintln("꽃이 핍니다.")
}
}
class Rose extends Flower { }
class RosePasta { }
class Basket<T extends Flower> {
private T item;
...
}
class Main {
public static void main(String[] args) {
// 인스턴스화
Basket<RosePasta> rosePastaBasket = new Basket<>(); // 에러
//상속 받으면 가능
Basket<Flower> genericBasket = new Basket<>();
genericBasket.getItem().bloom(); //사용가능
Basket<Rose> roseBasket = new Basket<>();
roseBasket.getItem().bloom(); //사용가능
}
}
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<>();
}
}
제네릭 메서드
클래스 전체를 제네릭으로 선언할 수도 있지만, 클래스 내부의 특정 메서드만 제네릭으로 선언할 수 있음
class Basket<T> { // 1 : 여기에서 선언한 타입 매개 변수 T와
...
public <T> void add(T element) { // 2 : 여기에서 선언한 타입 매개 변수 T는 서로 다른 것임
...
}
}
스코프를 이용해서 먼저 가까운곳을 먼저 찾음
메서드는 제네릭 타입을 지정할수도 지정하지 않을수도 있음
Basket<String> basket = new Bakset<>(); // 위 예제의 1의 T가 String으로 지정
basket.<Integer>add(10); // 위 예제의 2의 T가 Integer로 지정
basket.add(10); // 타입 지정을 생략할 수도 있음
클래스 타입 매개 변수와 달리 메서드 타입 매개 변수는 static 메서드에서도 선언하여 사용할 수 있음
class Basket {
...
static <T> int setPrice(T element) {
...
}
}
와일드카드
어떤 용도로든 사용할수있다! 즉 어떠한 타입으로든 대체될수 있는 타입 파라미터를 의미
ㄱㅣ호는 ? 로 와일드 카드 사용 할수 있음
일반적으로 와일드 카드는 extends 와 super 키워드를 조합하여 사용함
자바에서 구현되어 있는 코드 사용할때만 사용하게 됨!
'IT > JAVA' 카테고리의 다른 글
JAVA - 컬렉션 프레임 워크 (0) | 2024.12.02 |
---|---|
JAVA - Collection 3) 예외처리 (1) | 2024.11.29 |
JAVA - Collection 1) 열거형 (0) | 2024.11.29 |
JAVA - 객체 지향 심화 3) 추상화 (0) | 2024.11.27 |
JAVA - 객체 지향 심화 2) 캡슐화 (0) | 2024.11.27 |