상세 컨텐츠

본문 제목

[JAVA] 제네릭(Generic) 정리(1) - 기본

Spring/JAVA

by Chan.94 2022. 5. 30. 17:42

본문

반응형

제네릭(Generic)이란 데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법

 

List<String> stringList = new ArrayList<String>();
List<Integer> integergList = new ArrayList<Integer>();

우리는 <> 들어가는 타입을 지정하여 사용한다.

 

어떤 객체를 만들어 사용하려고 한다.

그 객체는 String 타입도 지원하고 싶고 Integer타입도 지원하고 싶고 많은 타입을 지원하고 싶다.

각각의 타입에 따라 객체를 만들어 사용할 것인가?

그건 너무 비효율적이다.

이러한 문제를 해결하기 위해 우리는 제네릭이라는 것을 사용한다.


 

제네릭(Generic)은 타입을 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다.

더 정확히는 타입의 경계를 지정한다.


장점

  • 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있다.
  • 클래스 외부에서 타입을 지정해주기 때문에 따로 타입을 체크하고 변환해줄 필요가 없다. 즉, 관리하기가 편하다.
  • 비슷한 기능을 지원하는 경우 코드의 재사용성이 높아진다.

 

사용방법

타입 설명
<T> Type
<E> Element
<K> Key
<V> Value
<N> Number

통상적으로 위와같이 사용한다.

 


 

public class GenericTest1 {

	public static void main(String[] args) {
		DevLog<String> devLog1 = new DevLog<String>();
		DevLog<Integer> devLog2 = new DevLog<Integer>();
		
		devLog1.setElement("DevLog");
		devLog2.setElement(100);
		
		System.out.println(devLog1.getElement());
		System.out.println(devLog1.getElement().getClass().getName());	//타입
		
		System.out.println(devLog2.getElement());
		System.out.println(devLog2.getElement().getClass().getName());	//타입
	}

}

class DevLog<T>{
	private T element;

	public T getElement() {
		return element;
	}

	public void setElement(T element) {
		this.element = element;
	}
	
}

 DevLog 객체를 생성할 때 <> 안에 타입을 지정한다.
 
devLog1객체의 DevLog의 T 제네릭 타입은 String으로 모두 변환된다.
devLog2 객체의 DevLog의 T 제네릭 타입은 Integer으로 모두 변환된다.

 

실행결과는 아래와 같다.

DevLog
java.lang.String
100
java.lang.Integer

외부에서 사용자에 의해 객체의 타입이 지정되는 것을 확인하였다.

 

다음으로는 타입의 경계를 지정하는 것을 알아보자.


제네릭(Generic)의 장점으로 '잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지할 수 있다'라고 하였다.

이때 사용하는 것이 extends, super, ?(물음표) 이다.

키워드 내용
extends 상한경계
super 하한경계
? 와일드카드 : 알수없는 타입

 

 

예시)

<K extends T>	// K와 T의 자손 타입만 가능 (K는 파라미터 타입으로 지정)
<K super T>	// K와 T의 부모 타입만 가능 (K는 파라미터 타입으로 지정)
<?> 		// 모든 타입 가능

 

public class GenericTest2 {

	public static void main(String[] args) {
		DevLogTest<B> devLog1 = new DevLogTest<B>(new B("B Developer"));	//OK
		DevLogTest<C> devLog2 = new DevLogTest<C>(new C("C Developer"));	//OK
//		DevLogTest<A> devLog3 = new DevLogTest<A>(new A("A Developer"));	//ERROR

		System.out.println(devLog1.getType().getClass().getName());
		System.out.println(devLog1.getType().name);
		System.out.println(devLog2.getType().getClass().getName());
		System.out.println(devLog2.getType().name);
	}

}

class DevLogTest<T extends B>{
	private T type;

	public DevLogTest(T t) {
		type = t;
	}

	public T getType() {
		return type;
	}

	public void setType(T type) {
		this.type = type;
	}

}

class A {
	String name;

	public A() {}
	public A(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
}
class B extends A{
	public B(String name) {
		super(name);
	}
}
class C extends B{
	public C(String name) {
		super(name);
	}
}

A -> B -> C 의 상속관계를 가지는 객체가 있다.

DevLogTest객체는 <T extends B> 키워드로 B객체와 B객체의 자손 객체만 가능하도록 경계를 지정하였다.

 

(pacakage path).B
B Developer
(pacakage path).C
C Developer

파라미터로 넘겨받은 T 가 각각 B와 C 객체인 것을 확인할 수 있다.


************에러************
DevLogTest<A> devLog3 = new DevLogTest<A>(new A("A Developer"));

************에러 메세지***********
Bound mismatch: The type A is not a valid substitute for the bounded parameter <T extends B> of the type DevLogTest<T>

 


[Spring & Spring Boot/JAVA] - [JAVA] 제네릭(Generic) 정리(2) - 와일드카드

반응형

관련글 더보기

댓글 영역

>