스프링 공부를 하다가 제네릭 개념이 나와 다시 정확히 짚고 넘어가려 한다.
컴파일시 타입을 체크해주는 기능(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은 형변환 에러이다.
분명 컴파일에는 에러가 없었는데, 실행하니 에러가 난다.
이게 바로 컴파일러의 한계이다. 컴파일은 실제로 뭐가 들어있는지 몰라서 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 str = null; // null로 초기화히자 말기
String str = ""; // 빈 문자열로 초기화하기
// 그래야지 길이를 출력할 때 에러가 나지 않음
int i = str.length()
위의 사진처럼, 빈 문자열을 만들고자 할 때 null로 초기화 하면 길이를 출력할 때 0 이 아닌 에러가 발생할 것이다.
따라서 빈 문자열, 빈 배열 등을 선언할 때 null로 초기화하지 말자!