제네릭

이재연·2021년 4월 11일
0

Java Basic

목록 보기
14/15

제네릭이란?

데이터 타입의 일반화이다. 컴파일 시점에서 미리 지정하는 방법이다.
Object 타입으로 사용하는 방법과 비교해 변환이나 검사 같은 작업을 생략할 수 있다.
타입 세이프(Type Safe)한 코드를 작성할 수 있다.

제네릭 사용법

파라미터는 어떤 네이밍을 써도 되지만 주로 E, K, T, V 등을 사용한다.

파라미터는 임의의 참조형 타입을 의미한다.

클래스 뒤에 <>를 붙이고 파라미터 명을 써준다.

public class MyClass<T>{
	private T t;

	public MyClass(T t){
		this.t = t;
	}
	
	public T get(){
		return this.t;
	}	
}

public static void main(String[] args) {
	MyClass<Integer> integerClass = new MyClass<>(1);      
	MyClass<String> stringClass = new MyClass<>("1");
	//컴파일 에러
	//MyClass<Integer> integerClass = new MyClass<>("1");  
	
	Integer integerType = integerClass.get();
	String stringType = stringClass.get();
	//컴파일 에러
	//String integerType = integerClass.get();		
}

제네릭 주요 개념

  • 바운디드 타입

제네릭 타입을 특정 타입의 서브 타입으로 제한하는 것

타입에 extends 키워드를 사용해 타입을 제한한다.

클래스, 인터페이스 모두 extends 키워드를 사용한다.

public class MyBounded<T extends Number>{
	private T t;

	public MyBounded(T t){
		this.t = t;
	}
	
	public T get(){
		return this.t;
	}	
}
public static void main(String[] args) {
	MyBounded<Integer> integerClass = new MyBounded<>(1);    
	//컴파일 에러  
	//MyBounded<String> stringClass = new MyBounded<>("1");
}
  • 와일드 카드

메소드에서 제네릭 타입의 파라미터를 받을 때 사용한다.

? 를 사용하여 임의의 파라미터 타입으로 받을 수 있다.

Upper Bounded Wildcard : 특정 클래스의 자식 클래스만 인자로 받을 수 있다.

Lower Bounded Wildcard : 특정 클래스의 부모 클래스만 인자로 받을 수 있다.

public static void main(String[] args) {
	MyClass<Integer> integerClass = new MyClass<>(1);   
	MyClass<String> stringClass = new MyClass<>("a"); 
	
	//unbounded wildcard
	printMyClass(integerClass);//1출력
	printMyClass(stringClass);//a출력

	//upper bounded wildcard
	printNumberClass(integerClass);//1출력
	//컴파일 에러
	//printNumberClass(stringClass);

	//lower bounded wildcard
	printIntegerClass(integerClass);//1출력
	//컴파일 에러
	//printIntegerClass(stringClass);
}

public void printMyClass(MyClass<?> mc) {
	System.out.println(mc.get());
}

public void printNumberClass(MyClass<? extends Number> mc){
	System.out.println(mc.get());
}

public void printIntegerClass(MyClass<? super Integer> mc) {
	System.out.println(mc.get());
}

제네릭 메소드 만들기

선언부에 제네릭 타입이 있는 메서드를 제네릭 메서드라고 한다.

public <T> void printInMyClass(MyClass<T> mc){
	System.out.println(mc.get());
}

반환 타입으로 제네릭 타입을 지정할 수도 있다.

public <T> T getInMyClass(MyClass<T> mc){
	return mc.get();
}

메서드에 사용된 제네릭 타입은 메서드 내에서 사용된다. 그래서 static 메서드에서도 사용 가능하다.

public static <T> T getInMyClass(MyClass<T> mc){
	return mc.get();
}

Erasure

제네릭은 컴파일 시점에만 유효하다. 컴파일 시점에 타입에 대한 정보를 정의하고 런타임 시점에는 소거하기 때문이다. 이 과정을 타입 소거(Type Erasure)라고 한다.

타입 소거는 아래 방식으로 진행된다.

  1. 먼저 제네릭 타입을 바인딩 된 형식의 파라미터로 변경한다.
  2. 만약 바인딩 되지 않았으면 Object로 변경한다.
  3. 필요하다면 타입 캐스팅 혹은 브릿지 메서드를 생성하기도 한다.

0개의 댓글