1. 타입 매개변수 제한
1.1 제네릭을 사용하지 않는 경우
- 장점 : 타입 안전성 X
- 단점 : 코드의 중복 O
package generic.ex3;
import generic.animal.Dog;
public class DogHospital {
private Dog animal;
public void set(Dog animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public Dog bigger(Dog target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
1.2 다형성 시도
- 다형성을 사용하여 코드의 중복 제거 시도
- 장점 : 코드 재사용 O
- 단점 : 타입 안전성 x
package generic.ex3;
import generic.animal.Animal;
public class AnimalHospitalV1 {
private Animal animal;
public void set(Animal animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public Animal getBigger(Animal target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
- 문제1 : 개 병원에 고양이 전달
dogHospital.set(cat);
- 문제2 : 다운 캐스팅 필요
dogHospital.set(dog);
Dog biggerDog = (Dog) dogHospital.getBigger(new Dog("멍멍이2", 200));
1.3 제네릭 도입과 실패
- 문제1 : 타입 인자로 어떤 타입이든 들어올 수 있다.
- 문제2 : 문제1로 인해 타입 매개변수를 Object로 가정하므로, Object의 기능만 사용할 수 있다.
∴ 타입 인자를 제한할 필요성이 생김
package generic.ex3;
public class AnimalHospitalV2<T> {
private T animal;
public void set(T animal) {
this.animal = animal;
}
public void checkup() {
// T의 타입을 메서드를 정의하는 시점에는 알 수 없다. Object의 기능만 사용 가능
animal.toString();
animal.equals(null);
// 컴파일 오류
//System.out.println("동물 이름: " + animal.getName());
//animal.sound();
}
public T getBigger(T target) {
// 컴파일 오류
return null;
//return animal.getSize() > target.getSize() ? animal : target;
}
}
1.4 타입 매개변수 제한
- 타입 안전성 문제
- 개 병원에 고양이 전달 -> 해결
- 다운 캐스팅 필요 -> 해결
- 제네릭 도입 문제
- 타입 인자로 어떤 타입이든 들어올 수 있다. -> 해결
- Object의 기능만 사용할 수 있다. -> 해결
package generic.ex3;
import generic.animal.Animal;
public class AnimalHospitalV3<T extends Animal> {
private T animal;
public void set(T animal) {
this.animal = animal;
}
public void checkup() {
System.out.println("동물 이름: " + animal.getName());
System.out.println("동물 크기: " + animal.getSize());
animal.sound();
}
public T getBigger(T target) {
return animal.getSize() > target.getSize() ? animal : target;
}
}
2. 제네릭 메서드
- 메서드를 호출하는 시점에 타입 인자를 전달해서 타입을 지정한다.
- 제네릭 타입
- 정의: GenericClass<T>
- 타입 인자 전달: 객체를 생성하는 시점
- 제네릭 메서드
- 정의: <T> T genericMethod(T t)
- 타입 인자 전달: 메서드를 호출하는 시점
- static 메서드에 타입 매개변수 사용 불가능
class Box<T> {
T instanceMethod(T t) {} //가능
static T staticMethod1(T t) {} //제네릭 타입의 T 사용 불가능
}
- 타입 매개변수 제한 가능
- 타입 추론 가능
- 제네릭 메서드가 제네릭 타입보다 우선순위가 높다. -> 모호하게 쓰지 말 것
3. 와일드카드
- 제네릭 타입을 조금 더 편리하게 사용할 수 있다.
- ?를 사용하여 정의한다. -> 여러 타입이 들어올 수 있다.
- 와일드카드는 이미 만들어진 제네릭 타입을 활용할 때 사용한다.
- 제네릭 메서드의 사용 과정은 매우 복잡하지만,
와일드카드는 매개변수로 제네릭 타입을 받을 수 있는 것이므로 단순하다.
package generic.ex5;
import generic.animal.Animal;
public class WildcardEx {
static <T> void printGenericV1(Box<T> box) {
System.out.println("T = " + box.get());
}
static void printWildcardV1(Box<?> box) {
System.out.println("? = " + box.get());
}
static <T extends Animal> void printGenericV2(Box<T> box) {
T t = box.get();
System.out.println("이름 = " + t.getName());
}
static void printWildcardV2(Box<? extends Animal> box) {
Animal animal = box.get();
System.out.println("이름 = " + animal.getName());
}
static <T extends Animal> T printAndReturnGeneric(Box<T> box) {
T t = box.get();
System.out.println("이름 = " + t.getName());
return t;
}
static Animal printAndReturnWildcard(Box<? extends Animal> box) {
Animal animal = box.get();
System.out.println("이름 = " + animal.getName());
return animal;
}
}
- 상한 제한과 하한 제한을 둘 수 있다.
static <T extends Animal> void printGenericV2(Box<T> box) {
T t = box.get();
System.out.println("이름 = " + t.getName());
}
static void printWildcardV2(Box<? extends Animal> box) {
Animal animal = box.get();
System.out.println("이름 = " + animal.getName());
}
package generic.ex5;
import generic.animal.Animal;
import generic.animal.Cat;
import generic.animal.Dog;
public class WildcardMain2 {
public static void main(String[] args) {
Box<Object> objBox = new Box<>();
Box<Animal> animalBox = new Box<>();
Box<Dog> dogBox = new Box<>();
Box<Cat> catBox = new Box<>();
// Animal 포함 상위 타입 전달 가능
writeBox(objBox);
writeBox(animalBox);
//writeBox(dogBox); // 하한이 Animal
//writeBox(catBox); // 하한이 Animal
Animal animal = animalBox.get();
System.out.println("animal = " + animal);
}
static void writeBox(Box<? super Animal> box) {
box.set(new Dog("멍멍이"
, 100));
}
}
4. 타입 이레이저
- 제네릭은 자바 컴파일 단계에서만 사용되고, 컴파일 이후에는 제네릭 정보가 삭제된다.
- 타입 매개변수에 instanceof, new 허용 x
class EraserBox<T> {
public boolean instanceCheck(Object param) {
return param instanceof T; // 오류
}
public T create() {
return new T(); // 오류
}
}
'study > Java' 카테고리의 다른 글
| LinkedList (0) | 2025.04.04 |
|---|---|
| ArrayList (0) | 2025.04.03 |
| Generic (0) | 2025.04.01 |
| Java에서 return문 누락으로 발생하는 오류와 해결 방법 (0) | 2025.03.05 |
| for문 (0) | 2025.02.20 |