Java Generic 제네릭

KHoney·2022년 9월 28일
0

Java

목록 보기
8/10
post-thumbnail

제네릭(generic)이란?

데이터 타입을 일반화한다(generalize)는 것을 의미한다.

클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하도록 해준다.

컴파일 시에 미리 타입 검사(type check)를 수행하면 다음과 같은 장점을 가진다

장점

  1. 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다.
    • 잘못된 타입에 대해 컴파일 단계에서 방지할 수 있다
  2. 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.
    • 클래스 외부에서 타입을 지정해주기 때문에 따로 타입 체크 및 변환이 필요없다.
  3. 비슷한 기능을 지원하는 경우 코드의 재사용성을 높일 수 있다.

사용

클래스 및 인터페이스 선언 과 생성

// 선언
public class MyGeneric<T> { ... }
public Interface MyGenericInterface<T> { ... }

// 생성
	...
	MyGeneric<String> = new 	MyGeneric<>();
	...

T 타입은 해당 블럭 { ... } 안에서 사용 가능하다.

또한 제네릭 타입의 갯수를 N 개로 선언해도 무관하다.

통용되는 알파벳과 의미

Generic 의 < > 괄호안에 어떠한 단어가 들어가도 상관이 없으나, 보통 한글자를 사용하고 통용되는 의미의 알파벳이 있다.

타입설명
Type
Element
Key
Value
Number

Generic 의 사용

제네릭 클래스

이제 클래스에서 Generic을 사용하여 구성하는 법을 알아보자

class MyGeneric<E> {
	
	private E element;	// 제네릭 타입 변수
	
	void set(E element) {	// 제네릭 파라미터 메소드
		this.element = element;
	}
	
	E get() {	// 제네릭 타입 반환 메소드
		return element;
	}
	
}

제네릭으로 선언된 E 타입을 가진 변수와 E 를 반환하는 메소드를 선언할 수 있다.

MyGeneric 클래스를 사용하는 객체에 따라서, E 제네릭에 원하는 type 을 넣어 해당 객체를 원하는 대로 사용할 수 있다.

MyGeneric<String> str = new MyGeneric<>();
MyGeneric<Integer> integer = new MyGeneric<>();
str.set("Hiroo");
integer.set(10);
String strClass = str.get().getClass().getName(); //java.lang.String
String integerClass = integer.get().getClass().getName(); // java.lang.Integer

메소드

public <T> T genericMethod(T o) {	// 제네릭 메소드
		...
}

// 선언 형식 은 다음과 같다
[접근 제어자] <제네릭타입> [반환타입] [메소드명]([제네릭타입] [파라미터]) {
	// 텍스트
}

처음 객체를 생성할때 <> 괄호안에 타입 파라미터로 전달한 타입에 의해 메소드의 Type T 또한 결정이 된다.

static 메소드

<> 에 넣은 파라미터에 관계없이 작동하는 메소드를 만들고 싶다면 static 메소드로 구현하면된다.

이때 class 에서 사용하는 Generic Name 과 겹칠경우 <> 를 통해 독립적인 타입임을 알려줘야한다.

class MyGeneric<E>{
	...

	static E genericMethod(E o) { // compile Error
			return o;
		}
	static <E> E genericStaticMethod(E o) { // compile OK
			return o;
		}
}

바운디드 제네릭 (Bounded Generics)

만약 제네릭 타입을 특정 범위 내로 좁혀서 제한하고 싶다면 어떻게 해야할까?

이 때 필요한 것이 바로 extends 와 super, 그리고 ?(물음표)다.

? 는 와일드 카드라고 해서 쉽게 말해 '알 수 없는 타입'이라는 의미다.

크게 세 가지 방식이 있다. 바로 super 키워드와 extends 키워드, 마지막으로 ? 하나만 오는 경우다. 코드로 보자면 다음과 같다.

<K extends T>	// T와 T의 자손 타입만 가능 (K는 들어오는 타입으로 지정 됨)
<K super T>	// T와 T의 부모(조상) 타입만 가능 (K는 들어오는 타입으로 지정 됨)

<? extends T>	// T와 T의 자손 타입만 가능
<? super T>	// T와 T의 부모(조상) 타입만 가능

<?>		// 모든 타입 가능. <? extends Object> 와 같은 의미

보통 이해하기 쉽게 다음과 같이 부른다.

? extends T : 상한 경계

? super T : 하한 경계

<?> : 와일드 카드(Wild card)

⚠️ 이 때 주의해야 할 게 있다. 와 는 비슷한 구조지만 차이가 있다. '유형 경계를 지정' 하는 것은 같으나 경계가 지정되고 **K는 특정 타입으로 딱 지정이 되지만, ?는 타입이 지정되지 않는다는 의미다.**
  • 타입 지정을 안하는데… 왜 안하지? 쓰는이유는? 두 개는 쓰임새가 약간 다릅니다. 유형을 지정하는경우에는 자바의 최상위 객체인 Object를 제외하고는 모두 상계(상한선)이 제한되지만, 와일드카드에서는 상한 하한 모두에서 쓸 수 있습니다. 그렇다보니 대개는 와일드카드는 super에서 많이 쓰입니다. 또한 특정 타입에 대해 참조할 필요가 없을 경우에는 와일드 카드가 유용하게 작용합니다 :)
profile
좋은 개발자가 되고싶은

0개의 댓글