제네릭이란?
- 데이터 형식에 의존하지 않고, 하나의 값이 여러 데이터 타입들을 가질 수 있도록 하는 방법
List<Integer> integerList = new ArrayList<>();
String 으로 되어 있는 리스트, Integer로 되어 있는 리스트들을 모두 하나하나 타입에 따라 만들 수는 없으니... 그 때마다 이 리스트는 어떤 형식이에요! 라고 지정해주는게 좋겠죠?
→ 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다.
public class ClassN<E>{
private E element
}
제네릭에는 그 때마다 타입들이 많이 존재합니다. 그럼 하나씩 간단하게 볼게요.
(사실 무의식적으로 사용하고 있고 이론적으로 알고있어야하나 싶긴 합니다...)
언바운드(무한한) 와일드카드 타입
어떤 타입이 오든 상관 없다는 뜻이라고 합니다.
예를 들어
1. Object클래스에서 제공되는 기능을 사용하여 구현 할 수 있는 메서드
2. 타입 파라미터에 의존적이지 않은 일반 클래스의 메소드를 사용하는 경우
private static void potato(List<?> var0) {
for (Object var2 : var0) {
System.out.print(var2 + " ");
}
}
바운드 타입 매개변수 (특정 타입으로 제한)
'특정 타입의 서브 타입으로만 제한을 시키겠다' 입니다.
public class ClassN<T extends Number>{
public void set(T value) {}
}
public static void main(String[] args) {
ClassN<String> integer = new ClassN<>();
// 컴파일 애러 -> Number의 서브타입만 지원한다.
integer.set(123);
}
재귀적 타입 바운드
재귀적 타입 바운드는 타입 매개변수가 자신을 포함하는 수식에 의해 한정될 수 있습니다.
- 타입의 자연율을 정의하는 comparable이 많이 사용됨
public interface Comparable<T> {
int compareTo(T o);
}
// T는 자신과 비교될 수 있는 요소를 정의한 것
static <T extends Comparable<T>> T max(List<T> list) {
}
// <T extends Comparable<T>> 자신과 비교될 수 있는 모든 타입 T
제네릭의 서브타이핑
List<Number>
public static void main(String[] args) {
List<Number> a = new ArrayList<>();
a.add(1);
a.add(1L);
}
public void test(ClassN<Number> n) {
}
test(new ClassN<Number>)
test(new ClassN<Integer>) // 불가능
ClassN<Integer>은 ClassN<Number> 의 서브 타입이 아님
둘다 object를 상속
→ 무공변 이기 때문이다.
공변성 | T’가 T의 서브타입이면 C<T’>는 C<T>의 서브타입이다. | <? extend Object> |
반공변성 | T’가 T의 서브타입이면, C<T>는 C<in T’>의 서브타입이다. 자기 자신과 부모 객체 허용 | <? super Person> |
무공변성 | C와 C<T’>는 아무 관계가 없다. |
- <? extend Object> 공변의 특징
- Object의 하위 타입이 올 수 있음 (Object, Person ...)
- <? super Person> 반공변의 특징
- Person의 상위 타입이 올 수 있음. (Person, Object)
- List<Object>와 List<Person>은 비공변이다. (배열은 공변임)
제네릭을 사용 할 수 없는 경우
public class GList<T> {
private Object[] objectList = new Object[5];
}
이런 경우 elementData 도 newT[5] 와 같이 생성하면 안될까?
대답은 안됩니다. 이유는 new 연산자 때문입니다. new 연산자는 heap영역에 충분한 공간이 있는지 확인하고 메모리를 확보하는데 그 공간을 얻을 때 타입을 알아야합니다. 즉 제네릭으로 배열을 생성할 수 없습니다.
static 변수에도 제네릭을 사용 할 수 없습니다.
static은 main함수가 실행될 때 메모리에 바로 올라가서 인스턴스에 종속되지 않는 클래스 변수입니다.
즉 모든 인스턴스가 공통된 저장공간을 공유합니다.
하지만 static 변수를 어느 경우에는 String 어느 경우에는 Integer로 사용 할 수 없습니다.
'언어 > 자바' 카테고리의 다른 글
예외처리(exception) (0) | 2021.09.16 |
---|---|
열거형(enum) (0) | 2021.09.16 |
직렬화 (Serialization) 와 역직렬화(Deserialization) (0) | 2021.09.13 |
thread에 대해서! (0) | 2021.09.11 |
자바 컬렉션(List, Map, Set) (0) | 2021.09.10 |