Java Generic - 메소드 활용하기
기존의 동물 병원.. Animal Hospital 작성한 것이 있다.
작성한 자바 코드는 제네릭 타입으로 사용하였으니, 제네릭 메소드로 변경해보도록 한다.
AnimalHospital.class - Before
public class AnimalHospital<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;
}
}
AnimalHospital.class - After
public class AnimalHospital {
public static <T extends Animal> void checkup(T t) {
System.out.println("동물의 이름 = " + t.getName());
System.out.println("동물의 몸무게 = " + t.getSize());
t.sound();
}
public static <T extends Animal> T bigger(T t1, T t2) {
return t1.getSize() > t2.getSize() ? t1 : t2;
}
}
- 제네릭 메소드로
public static <T extends Animal> void checkup(T t) {...}
선언하였다. - set 메소드로 받아올 원본이 사라졌으므로 매개변수로 Animal의 객체들을 받아 와야한다.
Main.class
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("강아지", 15);
Cat cat = new Cat("고양이", 8);
AnimalHospital.checkup(dog);
AnimalHospital.checkup(cat);
Dog newDog = new Dog("작은 강아지", 5);
Dog getBigDog = AnimalHospital.bigger(dog, newDog);
System.out.println("bigger = " + getBigDog);
}
}
동물의 이름 = 강아지
동물의 몸무게 = 15
멍
동물의 이름 = 고양이
동물의 몸무게 = 8
냥
bigger = Animal{name='강아지', size=15}
Dog getBigDog = AnimalHospital.<Dog>bigger(dog, newDog);
위의 코드처럼 명시적으로 제너릭을 넣지 않아도 동작하는 모습으로 타입 추론을 사용한다.
우선순위 - 제네릭 메소드, 제네릭 타입
둘 의 특징
- 정적 메소드에는 제네릭 메소드가 사용 가능
- 인스턴스 메소드는 제네릭 타입, 제네릭 메소드 사용 가능
Complex.class
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("강아지", 15);
Cat cat = new Cat("고양이", 8);
Complex complex = new Complex();
complex.set(dog);
complex.print(cat);
}
}
- 제네릭 타입 T로 선언하였다.
- 제네릭 메소드는 Z로 메소드에 선언하였다.
다음 호출 결과를 살펴보자.
Main.java
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("강아지", 15);
Cat cat = new Cat("고양이", 8);
Complex complex = new Complex();
complex.set(dog);
complex.print(cat);
}
}
animal.className = Dog
z.className = Cat
- 각각 타입과 메소드를 T, Z 분리해서 표현하였다.
제네릭 타입 설정
class ComplexBox<T extends Animal>
제네릭 메소드 설정
<Z> Z print(Z z)
다음으로 메소드 타입 모두 T 이름으로 통일시킨 경우 어떻게 되는지 살펴보자.
Complex.class - 제너릭 이름 통일
public class Complex<T extends Animal> {
private T animal;
public void set(T animal) {
this.animal = animal;
}
public <T> T print(T t) {
System.out.println("animal.className = " + animal.getClass().getName());
System.out.println("t.className = " + t.getClass().getName());
return t;
}
}
Main.java
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("강아지", 15);
Cat cat = new Cat("고양이", 8);
Complex complex = new Complex();
complex.set(dog);
complex.print(cat);
}
}
animal.className = Dog
t.className = Cat
이름 충돌로 덮어쓰거나 발생되지 않고 정상적으로 출력한다.
print() 제네릭 타입이 무관한 제네릭 메소드가 출력하고 있다.
결과로 제네릭 타입보다는 제너릭 메소드이 우선순위가 높다고 볼 수 있다.
번외로 제너릭 메소드에 적용되는 타입 매개변수 T 에는 파라미터 상한이 없다. Object로만 취급하므로 Animal의 getName() 이름을 호출할 수 없는 것을 살펴볼 수 있다.