ㆍ제네릭
- 타입 형 변환에 있어서 야기될 수 있는 문제를 사전에 차단하기 위해 만들어짐 (특정 타입만을 리턴할경우 확장성이 떨어지고 Object로 반환할 경우 일일이 캐스팅을 해줘야함)
- 제네릭 클래스를 선언 할 때 클래스명 뒤에 <T> 와 같은 형태로 선언 (public class Sample<T>)
- 이후 제네릭 클래스의 객체를 생성하거나 리스트와 같은 자료형을 만들 때 <> 안에 자료형을 지정해줌
(Sample<String> sample = new Sample<String>(); List<Integer> list = new ArrayList<Integer>();)
==> 객체 생성 시 명시적으로 타입을 지정해주기때문에 일일이 캐스팅을 할 필요가 없음
- 일반적으로 꺾쇠<> 안에는 기본 규칙이 존재함
- (E: 요소(Element, Collection에서 주로 사용) )
- K: 키
- N: 숫자
- T: 타입
- V: 값
- S, U, V: 2, 3, 4번째로 선언된 타입
- 메소드 선언 시 매개변수의 타입으로 <?> 을 적어주면 타입에 해당 변수의 타입에 관계없이 매개변수로 받을 수 있음. (하지만 받은 매개변수는 모든 참조 자료형의 부모인 Object 타입이 됨. 따라서, 이후 캐스팅이 필요, 아니면 instanceof로 인스턴스에 대한 타입을 확인)
- <? extends 타입> 으로 해당 클래스나, 해당 클래스를 상속받은 객체만 매개변수로 받을 수 있음. (Bounded Wildcards)
- 메소드 선언시 리턴값 앞에 <T>와 같은 제네릭한 타입을 선언해주면 타입에 관계없이 매개변수로 받을 수 있다.
(<?>과 다른점? => <?>은 Object로 매개변수가 선언되지만, 이 방법은 매개변수로 받은 객체의 타입에 따라 매개변수의 타입이 결정됨)
ex)) public <T> void greatMath(T num) => num으로 받아온 매개변수의 타입이 float라면 T가 Float 타입으로 치환되어 컴파일됨, 이 때 메소드내에서 선언된 T는 Float타입으로 치환 됨(T = Float)
ex)) public <T extends Calculator> void greatMath(NumClass<T> c) 와 같이 특정 클래스를 상속받은 타입만 받게할수도 있음
ㆍ+)
- <? extends 타입> 이 해당 타입의 자식클래스만 사용할 수 있었다면, <? super 타입>은 해당 타입의 부모 클래스만 사용 가능 (따라서,<? extends 타입>은 Upper Bounded Wildcards //<? super 타입>은 Lower Bounded Wildcards)
=> 오라클의 자바 공식문서 Upper Bounded Wildcards, Lower Bounded Wildcards 참고
- 제네릭 클래스를 선언할 때 타입을 꺾쇠<>안에 선언해주지 않아도 컴파일 자체는 가능(당연히 권장되지는 않지만 신경 써야함. IDE가 경고해준다.)
ex) Sample<String> sample = new Sample<String>();
ex) Sample sample = new Sample();
- C++, C#과 같은 언어와 달리, Java는 제네릭으로 Primitive Type(int, float, long, char)의 타입을 받을 수 없다. 그 이유는 제네릭을 컴파일 할 때 지정된 타입으로 안전하게 캐스팅을 할 의무가 있음. 따라서, 제네릭으로 선언된 <T>와 같은 타입을 Object로 바꾼 뒤(모든 참조 자료형의 부모) 그에 맞는 자료형으로 캐스팅하는 작업을 함.
** Stack Overflow 답변 참고
1. Answer is Object is superclass of all objects and can represent any user defined object.
2. Since all primitives doesn't inherit from "Object" so we can't use it as a generic type.
https://stackoverflow.com/questions/2721546/why-dont-java-generics-support-primitive-types
Why don't Java Generics support primitive types?
Why do generics in Java work with classes but not with primitive types? For example, this works fine: List<Integer> foo = new ArrayList<Integer>(); but this is not allowed: List<...
stackoverflow.com
- 제네릭하게 선언된 메소드에 파라미터로 정수(1)나 실수(1.3), 문자열("Jacava")같은 리터럴 값을 넘겨주면 컴파일러에서 알아서 해당 타입의 클래스인 Integer, Double, String 타입 으로 바꿔줌 (not primitive type)
참고
ㆍ"자바의 신 vol.2", 이상민 저자