포도가게의 개발일지
[JAVA] Generic 본문
반응형
제네릭
- 제네릭(Generic)은 클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법을 의미한다.
why?
- 제네릭 타입을 사용함으로써 잘못된 타입이 사용될 수 있는 문제를 컴파일 과정에서 제거할 수 있기 때문입니다. 자바 컴파일러는 코드에서 잘못 사용된 타입 때문에 발생하는 문제점을 제거하기 위해 제네릭 코드에 대해 강한 타입 체크를 합니다. 실행 시 타입 에러가 나는것보다는 컴파일 시에 미리 타입을 강하게 체크해서 에러를 사전에 방지하는 것이 좋습니다.
ArrayList list = new ArrayList(); //제네릭을 사용하지 않을경우
list.add(10);
Integer temp = (Integer) list.get(0); //타입변환이 필요함
ArrayList<Integer> list2 = new ArrayList(); //제네릭을 사용할 경우
list2.add(10);
temp = list2.get(0); //타입변환이 필요없음
how?
- 제네릭 타입은 타입을 파라미터로 가지는 클래스와 인터페이스를 말합니다. 제네릭 타입은 클래스 또는 인터페이스 이름 뒤에 < > 부호가 붙고 사이에 타입 파라미터가 위치합니다.
public class 클래스명<T> {...}
public interface 인터페이스명<T> {...}
public class SimpleArrayList {
private int size;
private Object[] elementData = new Object[5];
public void add(Object value) {
elementData[size++] = value;
}
// 타입을 object로 리턴하게 된다
public Object get(int idx) {
return elementData[idx];
}
}
public class SimpleArrayListTest {
public static void main(String[] args) {
SimpleArrayList list = new SimpleArrayList();
list.add(50);
list.add("100");
// object로 return 되게 되면서 형변환작업이 필요하다
// 하지만 String으로 넣게 되버리면 String -> Integer로 캐스팅 에러가 발생하는 일이 생긴다.
// 하지만 이것을 컴파일시 잡을수없고 런타임 중에 error가 발생한다.
Integer value1 = (Integer) list.get(0);
Integer value2 = (Integer) list.get(1);
System.out.println(value1 + value2);
}
}
// 이를 해결 하기 위해
// generic type을 받아와
public class GenericArrayList<T> {
// object 타입으로 어떤 value든 받을수있고
// 그러면 Object도 T로 쓰게 되면 되는데 왜 Object로 쎃을까?
// new 연산자는 heap 영역에 충분한 공간이 있는지 확인한 후 메모리를 확보하는 역할을 한다.
// 충분한 공간이 있는지 확인하려면 타입을 알아야한다. 그런데 컴파일 시점에 타입 T 가 무엇인지
// 알 수 없기 때문에 new T[5] 와 같이 제네릭으로 배열을 생성할 수는 없다.
private Object[] elementData = new Object[5];
private int size;
// 형변환 없이 사용할수있게 만들어 준다.
public void add(T value) {
elementData[size++] = value;
}
// return 형변환 없이 사용할수있게 만들어 준다.
public T get(int idx) {
return (T) elementData[idx];
}
}
디컴파일한 결과!(Test.java -> Test.class -> decompile)
Test.java
class Test {
public static void main(String[] args) {
GenericArrayList<Integer> intList = new GenericArrayList<>();
intList.add(1);
intList.add(2);
int intValue1 = intList.get(0); // 형변환이 필요없다
int intValue2 = intList.get(1); // 형변환이 필요없다
}
}
decompile
class Test {
Test() {
}
public static void main(String[] var0) {
GenericArrayList var1 = new GenericArrayList(); // 제네릭이 사라졌다
var1.add(1);
var1.add(2);
int var2 = (Integer)var1.get(0); // 형변환이 추가되었다
int var3 = (Integer)var1.get(1); // 형변환이 추가되었다
}
}
* 제네릭을 사용하면 컴파일러가 형변환을 알아서 진행한다는 것을 확인했다.
한정적 타입 매개변수
- GenericArrayList 가 Number 의 서브클래스만 타입으로 가지도록 하고 싶은 경우 아래와 같이 제네릭의 타입을 제한할 수 있다.
public class GenericArrayList<T extends Number>
타입인자
https://yaboong.github.io/java/2019/01/19/java-generics-1/
'Spring boot' 카테고리의 다른 글
[Java] JVM과 자바 메모리 구조 (0) | 2022.01.22 |
---|---|
[Spring] java.lang.IllegalStateException: Failed to load ApplicationContext (0) | 2022.01.21 |
[Spring]Transaction? (0) | 2022.01.20 |
[JAVA] Annotation? (0) | 2022.01.20 |
[JAVA] 빌드 과정 (0) | 2022.01.13 |
Comments