Generic vs Object
Generic과 Object에서 가장 큰 차이점은 타입을 체크하는 타이밍이 다르다는 것입니다.
Generic
.java파일을 컴파일하게 되면 제네릭을 전부 타입 검사 후 제거하게 된다. 따라서 이후 .class파일에서는 제네릭이 남아 있지 않는 상태가 된다.
Test<String> a = new Test<>();
a.setValue("한글");
String aValue = a.getValue();
Object
컴파일한 후 런타임을 도중 타입체크를 해줘야 한다. 또한 값을 사용하기 위해 Casting을 해주어야 하는데, 성능 저하에 큰 영향을 준다.
ObjectTest ot = new ObjectTest();
ot.setValue("한글");
String han = ot.getValue(); // ERROR:
String hanString = (String)ot.getValue(); // Type cast를 해주어야 한다.
ArrayList에서는 T[]가 아닌 Object[]를 사용하는 이유는?
ArrayList은 내부적으로 Object[]를 사용한다.
Object[] elementData = new Object[size];
public E get(int i) {
return (E) elementData[i];
}
// Main
String str = list.get(0);
하지만 T[]를 사용한다면 어떻게 될까?
E[] elementData = (E[])new Object[size];
public E get(int i) {
return (E) elementData[i];
}
// Main
String str = list.get(0);
이상태에서 컴파일을 하게 된다면
String[] elementData = (String[])new Object[size];
public String get(int i) {
return (String) elementData[i];
}
// Main
String str = list.get(0);
이런식으로 변환되는데 문제는 런타임에서입니다.
Object[]을 String[]로 변환하려다 보니 다운캐스팅을 하게 되고 Object는 String을 위한 특정 클래스나 메서드 속성이 없어서 런타임에서 변환할 수 없고 ClassCastException이 발생합니다.
따라서 T[]를 통해서 사용하지 않고 Object[]를 사용하여 구현되었습니다.
Object 공변 vs Generic 불공변
Obejct배열
Object[] objArray = new Integer[3];
objArray[0] = "String"; // ERROR
Integer는 Object를 상속받은 클래스이므로 위와 같이 UpCasting이 가능합니다. 따라서 컴파일 타임에서는 아무 문제가 없지만 문자열 값을 넣게 되면 런타임에서 ArrayStoreException이 발생하게 됩니다.

여기서 Upcasting이 가능한 이유는 공변(Convariant)하기 때문입니다.
공변한 배열의 특징
공변하기 때문에 컴파일 타임에서 에러를 잡을 수 없습니다. 하지만 불변하게 만든다면 위와 같은 Upcasting에 대해서 못하게 되므로 다형성 프로그래밍을 방지하게 된다.
Generic 불공변
ArrayList<Object> arrayList = new ArrayList<Integer>();
Generic에서는 위 코드를 작성하게 되면 컴파일 타임에서 에러가 잡힙니다. 이는 Generic타입은 불공변(invariant)하기 때문이다.
따라서 Generic은 컴파일을 거치면서 똑같은 클래스에 대해서만 나오기 때문에 아래와 같이 된다.
ArrayList<Integer> intArrayList = new ArrayList<Integer>();
// => ArrayList intArrayList = new ArrayList();
ArrayList<String> stringArrayList = new ArrayList<String>();
// => ArrayList stringArrayList = new ArrayList();
결국
자바 배열의 공변성을 지원한 이유는
- 기존 C언어 배열 및 하위 호환성을 유지하고 객체 배열을 생성할 수 있기 때문이다.
- 배열은 타입 안전성을 보장하지 못하므로 제네릭을 통해 불공변성을 지원합니다.
이렇게 만든 이유는 결국 자바가 추구하는 타입 안정성을 위해서 입니다.
또한 제네릭 배열의 경우 컴파일러가 제네릭 타입을 제거하게 되는데 이때 타입 추론 때문에 지원되지 않는다.
제네릭 배열을 생성하기 위해서는 타입 캐스팅을 사용해야하는데 , 안전하지 않아서 권장되지 않는다.
'JAVA > 자바스터디' 카테고리의 다른 글
[자바스터디] 쓰레드 동작 순서 (0) | 2023.01.29 |
---|---|
[자바스터디] 쓰레드 (0) | 2023.01.28 |
[자바스터디] Generic (0) | 2023.01.28 |
[자바 스터디] for vs foreach vs iterator (0) | 2023.01.28 |
[자바스터디] Collection - Collections (0) | 2023.01.22 |