[자바의 정석] 지네릭스(Generics)란?

myeonji·2022년 2월 10일
0

JAVA

목록 보기
9/9

스프링 공부를 하다가 제네릭 개념이 나와 다시 정확히 짚고 넘어가려 한다.

> 지네릭스란?

컴파일시 타입을 체크해주는 기능(compile-time type check)
객체의 타입 안정성을 높이고 형변환의 번거로움을 줄여줌

public class test {

	public static void main(String[] args) {
		ArrayList<Tv> tvList = new ArrayList<Tv>();
		
		tvList.add(new Tv()); // 가능
		tvList.add(new Audio()); // 컴파일 에러. Tv 외에 다른 타입은 저장 불가
	}
}

ArrayList<>는 Object 배열을 가지고 있어서 모든 종류 객체를 저장할 수 있다.
Tv라는 타입을 지정하고 객체를 생성하면 tvList에는 Tv만 저장이 가능한 것이다.


import java.util.ArrayList;

public class test {

	public static void main(String[] args) {
		ArrayList list = new ArrayList();
		list.add(10);
		list.add(20);
		list.add("30"); // String을 추가
		
		Integer i = (Integer)list.get(2); // 컴파일 OK
		
		System.out.println(list);
	}
}

위의 코드에서 list에 String을 추가해도 컴파일 에러가 없다.
또한 Integer i = (Integer)list.get(2); 부분에서 list.get(2)의 반환 타입은 Object 이다.
이를 (Integer)를 통해 형변환 했으므로 컴파일에서는 에러가 없다.

📌 하지만, 이를 실행하면 아래와 같은 에러가 난다.
Exception in thread "main" java.lang.ClassCastException:

ClassCastException형변환 에러이다.
분명 컴파일에는 에러가 없었는데, 실행하니 에러가 난다.

  • 컴파일 입장 : list.get(2)의 반환 타입은 Object 이다. 이를 (Integer)를 통해 형변환 했으므로 컴파일에서는 에러가 없다.
  • 런타임(실행시) 입장 : 실제로 list.get(2) 타입은 String이다. 따라서 형변환에러가 발생한다.

이게 바로 컴파일러의 한계이다. 컴파일은 실제로 뭐가 들어있는지 몰라서 Object로 꺼내기 때문이다.

💡 실행시에 발생하는 에러를 어떻게 하면 컴파일에 잡을 수 있을까?

-> 지네릭스!!

지네릭스를 적용하여 ArrayList 타입을 < Integer >로 넣었더니 list.add("30")인 String 추가에 빨간 줄이 그어지는 것을 볼 수 있다.
즉, 컴파일 단계에서 에러를 잡을 수 있다! -> 타입 체크 강화됨!

Integer i = list.get(2); // 형변환 생략 가능

또한 이미 ArrayList 타입을 Integer로 해놓았기에 위처럼 형변환 생략이 가능하다.

public class test {

	public static void main(String[] args) {
		ArrayList<Object> list = new ArrayList<Object>();
		list.add(10);
		list.add(20);
		list.add("30"); // String을 추가
		
		String i = (String)list.get(2); // 컴파일 OK
		
		System.out.println(list);
	}
}

만약 타입을 Object라고 한다면 여러 종류의 객체를 저장할 수 있다. 대신 꺼낼 때는 해당 값에 맞게 형변환하여 꺼내야 한다.
위의 코드에서 인덱스 2의 값을 꺼내기 위해 형변환은 String으로 한 것을 볼 수 있다.

지네릭 기능은 모든 클래스에 해당하는 것은 아니고 클래스 안의 Object 타입이 있는 것들은 일반클래스에서 지네릭클래스로 바꿀 수 있다.
예) ArrayList(일반클래스) -> ArrayList< E >(지네릭클래스)


지네릭스를 왜 사용해야 할까?

에러는 컴파일 타임에서 발견하는 것이 좋다.

❓❗ 실행 중(런타임) 발생하는 에러 중에서 어떻게 하면 이를 컴파일 단계에서 발견할 수 있도록 끌어올 수 있을까? 를 해결하는 것이 지네릭스이다.

ClassCastException(형변환에러)를 지네릭스로 컴파일 단계에서 에러를 발견하도록 해결할 수 있다.

<참고>
NullPointerException은 자주 등장하는 에러이다.

  • String을 예시로 보면,
String str = null; // null로 초기화히자 말기
String str = ""; // 빈 문자열로 초기화하기

// 그래야지 길이를 출력할 때 에러가 나지 않음
int i = str.length()

위의 사진처럼, 빈 문자열을 만들고자 할 때 null로 초기화 하면 길이를 출력할 때 0 이 아닌 에러가 발생할 것이다.

  • 배열도 마찬가지이다!

따라서 빈 문자열, 빈 배열 등을 선언할 때 null로 초기화하지 말자!

0개의 댓글