[Java] 제네릭 심화 문법

YoungMinKim·2020년 11월 8일
0
post-thumbnail

제네릭 2-1

제네릭의 심화 문법

  • 제네릭 클래스 역시 상속이 가능하다.
  • Instance생성 시 < T >는 어떻게 해야 하는가?
  • 상속 관계로 이루어진 상황에서, 부모 클래스의 자료형이 자식 클래스의 자료형과 같아야 한다.
    • 즉, 자료형이 같아야 파생되는 상속 관계가 생성이 된다.

타켓 타입

  • 참조 변수의 형 Box< Integer >를 기반으로 makeBox 메소드의 T를 결정하게 된다.
  • 따라서 이를 가리켜 타켓 타입이라 한다.

와일드카드(제네릭 메소드 vs 일반 메소드)

  • < T >로 들어오는 인자가 다르면, 상속 관계가 형성 될 수 없다.
  • < T >는 컴파일러가 결정해주는 것이다.
    • 제네릭 클래스는 Instance화를 진행 할때 결정이 된다.
    • 제네릭 메소드는 메소드 호출 시 결정이 된다.

와일드카드

  • 와일드카드는 제네릭과 유사한 점이 많다, 또한 제네릭 메소드와의 결합을 통해 막강한 파워 생성.
  • 와일드카드< ? >는 어떠한 자료형도 받을 수 있다는 것을 의미한다.
  • 와일드카드 기반 메소드의 정의가 더 간결하다는 장점이 있다.

기능적으로는 두 메소드 완전 동일

public static <T> void peekBox(Box<T> box){
	System.out.println(box);
} // 제네릭 메소드의 정의

public static void peekBox(Box<?> box){
	System.out.println(box);
} // 와일드카드 기반 메소드 정의

와일드 카드의 상한과 하한의 제한 : Bounded Wildcards

  • 제네릭에서는 제한하는 방법이 한 가지밖에 없었다.
    • extends
  • 하지만 와일드카드는 두 가지를 통해 제한을 할 수 있다.
    • extends
    • super

하한 제한된 와일드카드

예시 1-1

public static void peekBox(Box<? super Integer> box){
	System.out.println(box);
}
  • extends상한 제한으로, Integer이거나 Integer를 상속하는 하위 계층으로 제한 한다.
  • super하한 제한으로, Integer이거나 Integer가 상속하는 상위 계층으로 제한 한다.

와일드카드 제한의 이유 설명을 위한 도입

예시 1-1

class Box<T> {
	private T ob;
		
	public void set(T o) {
		ob = o;
	}
		
	public T get() {
		return ob;
	}
}

class Toy {
	public String toString(){
		return "I am a Toy";
	}
}

class BoxHandler {
	public static void outBox(Box<Toy> box){
		Toy t = box.get();  // 상자에서 꺼내기
		System.out.println(t);
	}
	public static void inBox(Box<Toy> box, Toy n){
		box.set(n) // 상자에 넣기
	}
}

상한 제한의 목적

예시 1-1

class Box<T> {
	private T ob;
	public void set(T o ) { ob = o; }
	public T get() { return ob; }
}
...

public static void outBox(Box<? extends Toy> box){
	box.get(); // 꺼내는 것! OK
	box.set(new Toy()); //넣는 것! ERROR
}

class Car extends Toy {...}   // 자동차 장난감
class Robot extends Toy {...} // 로봇 장난감

// 다음과 같이 정리하자!
Box<? extends Toy> box 대상으로 넣는 것 불가!!

상한 제한을 하면 꺼내는 것은 가능하지만, 값 셋팅은 불가능하다.

  • 왜 값을 꺼낼수는 있고, 셋팅은 불가능한가?
  • 개인적으로 생각 해보길.

하한 제한의 목적

예시 1-1

class Box<T> {
	private T ob;
	public void set(T o ) { ob = o; }
	public T get() { return ob; }
}
...

public static void inBox(Box<Toy> box, Toy n){
	box.set(n) // 상자에 넣기
	Toy myToy = box.get(); // **꺼내는 것! Error**
}
	
// 다음과 같이 정리하자!
Box<? super Toy> box 대상으로 꺼내는 것 불가!

하한 제한을 하면 셋팅은 가능하지만, 꺼내는 것은 불가능하다.

  • 왜 값을 셋팅할 수 있고, 꺼내는 것은 불가능한가?
  • 개인적으로 생각 해보길.
  • 자식 클래스의 참조 변수로, 부모 클래스의 인스턴스를 참조한다.
    • 어떤 인자가 들어올지 모르는 상황이다.
    • 또한 무엇이 반환 될지 모르는 상황이다.

상한 제한과 하한 제한의 좋은 예

class BoxcontentsMover {
	// from에 저장된 내용물을 to로 이동
	
	public static void moveBox(Box<? super Toy>to, Box<? extends Toy> from){
		to.set(from.get());
	}
}

// <? super Toy> : 하한 제한
// <? extends Toy> : 상한 제한

제한된 와일드카드 선언을 갖는 제네릭 메소드 : 도입

다음 형태로 메소드 오버로딩 불가능하다

  • 기존 제네릭에 영향을 주지않고 업데이트를 하기 위해 불편한 점을 감안한다.
  • 기존 코드를 유지하기 위해 살짝 불편한 부분이 생겼다.
  • Box< ? extends Toy> box
  • Box< ? extends Robot> box
    • 메소드 오버로딩을 지원하지 않는다.
    • 컴파일러가 위 부분을 싹 지워버린다.
    • Type Erasure! 라는 용어로 알려져있다.

와일드 카드 선언을 갖는 메서드를 제네릭으로

  • ? extends 선언이 들어가면 상한 제한 → Box< T >
    • 상한 제한은 꺼내는 것만 가능하다.
    • 하한 제한은 셋팅하는 것만 가능하다.

제네릭 인터페이스의 정의와 구현

  • 핵심 : 제네릭으로 인터페이스도 구현이 가능하다.
profile
https://ym1085.github.io

0개의 댓글