제너릭(Generic)을 사용하는 이유

Choizz·2023년 2월 3일
0

Java

목록 보기
2/4

제너릭(Generic)

자바로 개인 프로젝트를 하다 보면, 인터페이스에 제너릭을 사용해야하는 경우가 있다. 그런데 사실 제너릭은 컬렉션에서만 사용해보고 제너릭을 사용해서 인터페이스나 클래스를 만들어 본 적은 없었다. 그래서 제너릭을 복습하는 차원에서 포스팅을 해보려고 한다.

이번 포스팅은 제너릭을 사용하는 이유에 대해서 이다.

우선, 공식 문서에서 제너릭을 사용하는 이유는 다음과같다.
1. 컴파일 타임에 타입을 검사할 수 있다.
2. 캐스트를 사용하지 않아도 된다.


1. 컴파일 타임에 타입을 검사할 수 있다.

첫 번째 이유에 대해 생각을 해보자.
보통 자바의 컬렉션에서 제너릭을 사용한다. 그렇다면 제너릭을 컬렉션에서 왜 사용하는 걸까?

  • 일단 컬렉션은 요소(Element), 즉, 객체들의 저장소 역할을 한다.
  • 제너릭을 사용함으로써 컬렉션에 들어가는 객체를 생성 시점에 선언함으로써 컴파일 시점에 타입을 체크할 수 있게 해준다.
    //제너릭을 사용함으로써 컴파일 시점에 타입을 체크할 수 있다.
	List < String > lists = new ArrayList<>();
	lists.add("문자열 타입");
	lists.add(123); //컴파일 에러
    
	// 제너릭을 사용하지 않는다면 한 컬렉션에 다른 타입의 요소가 들어가는 것을 컴파일 에러가 아닌 런타임에 발견한다.    
	List lists = new ArrayList();
	lists.add("문자열 타입");
	lists.add(123);

2. 캐스트를 사용하지 않아도 된다.

두 번째 이유를 이해하기 위해서 제너릭을 사용하지 않는 경우를 먼저 살펴보자.

제너릭을 사용하지 않을 경우

  • 임의의 클래스가 있다고 가정해 보자.
  • 제너릭을 사용하지 않고 여러 객체를 사용할 수 있으려면 Object 객체를 사용해야 할 것이다.
public class NoGeneric {

	private Object object;

	public void setObject(Object object) {
		this.object = object;
	}

	public Object getObject() {
		return object;
	}
}

	NoGeneric noGeneric1 = new NoGeneric();
	noGeneric1.setObject("문자열");
	String a = (String) noGeneric1.getObject(); //String 타입으로 캐스팅

	NoGeneric noGeneric2 = new NoGeneric();
	noGeneric2.setObject(123);
	Integer b = (Integer) noGeneric2.getObject(); //Integer 타입으로 캐스팅

	NoGeneric noGeneric3 = new NoGeneric();
	noGeneric3.setObject(1.1);
	Double c = (Double) noGeneric3.getObject(); //Double 타입으로 캐스팅

위 코드를 보면 그냥 캐스팅 하면 안되나?? 라고 생각할 수 도 있지만, 이렇게 다운 캐스팅하는 것 또한 런타임에 오류가 발생할 가능성이 있기 때문에 지양하는 것이 좋다.


	NoGeneric noGeneric1 = new NoGeneric();
	noGeneric1.setObject("문자열");
    
	//실제로 문자열 타입이어야 하지만 Intger 타입으로 해도 컴파일 오류가 나지 않고 런 타임에 오류를 발견한다.
	Integer a = (Integer) noGeneric1.getObject();
	String a = (String) noGeneric1.getObject();

제너릭을 사용하는 경우

제너릭을 사용하는 경우를 살펴 보면, 아래 코드와 같이 표현할 수 있다. Object가 들어갔던 타입에 T라는 알파벳을 적었다.

public class YesGeneric<T> {

	private T object;

	public void setObject(T object) {
		this.object = object;
	}

	public T getObject() {
		return object;
	}
}

이렇게 제너릭 타입으로 작성을 하게 되면 캐스팅을 하지 않아도 되고, 컴파일에 오류를 발견할 수 있다.


	YesGeneric < String > yesGeneric1 = new YesGeneric<>();
	yesGeneric1.setObject("문자열");
	String a = yesGeneric1.getObject();

	YesGeneric < Integer > yesGeneric2 = new YesGeneric<>();
	yesGeneric2.setObject(1);
	Integer b = yesGeneric2.getObject();

	YesGeneric < Double > yesGeneric3 = new YesGeneric<>();
	yesGeneric3.setObject(1.1);
	Double c = yesGeneric3.getObject();

정리

  • 공식 문서에 명시된 제너릭을 사용해야 하는 이유를 살펴보았다.
  • 제너릭을 사용함으로써 런 타입에 발생할 수 있는 오류들을 컴파일 타임에 발견함으로써 에러 컨트롤을 더 잘할 수 있게 됐다.

Reference

profile
집중

0개의 댓글