Generic method와 와일드 카드

야부엉·2024년 12월 4일
post-thumbnail

1. Generic 메서드

public static <T> T genericMethod(T t) {
	System.out.println("generic print: " + t);
	return t;
}
public static <T extends Number> T numberMethod(T t) {
	System.out.println("bound print: " + t);
	return t;
}
  • Generic 메서드는 위의 코드와 같이 Generic 타입과 유사하게 상향 경계를 사용할 수 있어 타입 인자 범위를 지정할 수 있지만,Generic 타입과는 다른 기능을 제공한다.
  • 가장 큰 차이점은 Generic 클래스는 객체를 생성하는 시점에 타입 인자를 전달하지만, Generic 메서드는 메서드를 호출하는 시점에 타입 인자를 전달한다.
  • Generic Method를 사용할 때는 아래의 코드와 같은 형식으로 사용되고, 두번째 방법처럼 타입 추론을 제공하기 때문에 생략이 가능하다.
		Integer integer = GenericMethod.<Integer>genericMethod(i);
		Integer integer2 = GenericMethod.numberMethod(10);
  • 결론적으로 Generic 클래스와 같이 호출하는 시점에 타입을 지정할 수 있으며 타입 인자를 통해 메서드의 변수 타입을 설정한다.

2. static 메서드와 인스턴스 메서드

  • Generic 메서드는 static 메서드와 인스턴스 메서드 모두에 사용될 수 있다. 여기서 주의해야할 점은Generic 클래스의 static 메서드에 Generic 타입 매개변수는 사용할 수 없다는 것이다.
  • 위의 원인은 JVM 메모리 공간을 생각하면 쉽게 알 수 있다.
  • 우리가 만든 클래스는 static 영역에 생성되고, new 연산자를 통해 Heap 영역에 생성됩니다. static 키워드를 사용한 것도 마찬가지로 static 영역에 할당되고, 모든 객체가 공유하는 형태를 지닙니다. 그리고 Generic 클래스는 타입인자를 new 연산자를 통한 객체 생성 시점에 전달하기 때문에, 클래스 내부에 있는 static Method에서는 이를 알지 못합니다.

3. Generic method와 Generic class의 우선 순위

  • Generic method와 Generic class가 동시에 사용되는 클래스 일때는 어떤 타입 인자가 우선순위로 잡힐지 궁금할 수 있다.
public class ComplexBox <T extends Animal>{

	private T animal;

	public void set(T animal) {
		this.animal = animal;
	}
    
	public <T> T printAndReturn(T t){
		System.out.println("animal.className = " + animal.getClass().getName());
		System.out.println("t.className :" + t.getClass().getName());
		return t;
	}
}


	public static void main(String[] args) {
		Dog dog = new Dog("멍멍이", 100);
		Cat cat = new Cat("냐옹이", 50);

		ComplexBox<Dog> hospital = new ComplexBox<>();
		hospital.set(dog);

		// Generic 타입보다 Generic 메서드가 더 높은 우선순위를 가진다.
		// 프로그래밍에서는 가까운거 좀 더 구체적인게 우선순위가 높다.
		Cat returnCat = hospital.printAndReturn(cat);
		System.out.println("returnCat = " + returnCat);

	}
  • 위의 Generic 클래스가 있다고 했을 시에, 아래의 main을 실행하면, 아래와 같은 결과값을 얻을 수 있다. 즉, 우선순위 기준으로는 generic method가 높다.

4. 와일드 카드

  • 와일드 카드는 Generic 타입을 조금 더 편리하게 사용할 수 있는 도구로, 여러 타입을 사용할 수 있다는 장점이 있다.
  • 아래의 예시 코드를 보면,
	static <T> void printGenericV1(Box<T> box) {
		System.out.println("T = " + box.get());
	}

	// 와일드 카드
	static void printWildcardV1(Box<?> box) {
		System.out.println("? = " + box.get());
	}
  • 첫 번째는 Generic 메서드고, 두번째는 와일드 카드를 사용한 메서드다.
  • 와일드 카드도 매개변수 타입 범위를 지정할 수 있으며, 위와 같이 범위를 지정하지 않은 것은 비제한 와일드 카드라고 한다. 즉, 범위를 지정하지 않아 모든 타입들을 받을 수 있으며 ? == <? extends Object>와 의미가 같다.
  • 둘이 실행하면, 같은 결과가 나온다. 그렇다면 왜 Generic 메서드가 있는데 와일드 카드를 쓸까?
  • 위의 예시를 통해 보면, printGenericV1(Box<T> box)는 타입 매개변수가 존재하며, 호출 시점에 타입 인자를 전달 받아 타입을 결정하는 복잡한 과정이 있다. 그러나 printWildcardV1(Box<?> box)를 사용하면, 와일드 카드는 일반적인 메서드에서도 사용 할 수 있고, 단순히 매개변수로 Generic타입을 받는 것 뿐이기 때문에 타입을 결정하는 복잡한 과정이 작동하지 않는다. 즉, 단순히 매개변수로 Generic 타입을 사용하는 일반적인 메서드라는 것이다.

5. 와일드 카드에서의 상한, 하한

  • 와일드 카드도 아까 얘기했다시피 매개변수 타입 범위를 제한 할 수 있다.
  • 첫 번째로, 상한 경계에 대해서 살펴보자.
	static Animal printAndReturnWildcard(Box<? extends Animal> box) {
		Animal animal = box.get();
		System.out.println("이름 = " + animal.getName());
		return animal;
	}
  • 위의 코드와 같이 Box<? extends Animal> box같이 표현하고, 매개변수 타입 범위를 Animal 클래스 포함 그 자식들까지만 들어올 수 있다라고 제한한다. 즉, 최고 기준을 Animal 타입으로 설정한 것이다.

  • 여기서 살펴봐야할 것은 box.get()의 반환타입인데, Generic Method와 다르게 반환 타입이 범위 기준 가장 최상위 클래스 타입으로 반환하는 것을 알 수 있다.

  • 두 번째로, 하한 경계에 대해서 살펴보자.

	static Animal printAndReturnWildcard(Box<? super Animal> box) {
		Object animal = box.get();
		return animal;
	}
  • 위의 코드와 같이 Box<? super Animal> box같이 표현하고, 매개변수 타입 범위를 Animal 클래스 포함 타입 중 최상위인 Object까지 들어올 수 있다라고 제한한다. 즉, 최소 기준을 Animal 타입으로 설정한 것이다.
  • 여기서도 살펴봐야할 것은 box.get()의 반환타입인데, 위와 같이 기준 최고 타입인 Object를 반환하는 것을 알 수 있다.

출처

김영한의 실전 자바 - 중급 2편

profile
밤낮없는개발자

0개의 댓글