제네릭이란?
이 글을 보러 오신분들은 대부분 자바를 공부하면서 제네릭이 뭔지 궁금해서 들어온 분들이실겁니다.
제네릭(generic)이란 데이터의 타입을 일반화한다(generalize)는 것을 의미합니다.
이렇게 적으면 아마 이해가 어려우실겁니다.
사실 우리가 흔히 사용하는 List, Map, Set 등의 컬렉션에서 자주 볼 수 있습니다.
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();
Set<Double> set = new HashSet<>();
}
객체<타입> 객체명 = new 객체<타입>();
이 형식에서 < > 이것이 바로 제네릭 입니다.
즉 제네릭은 클래스 외부에서 사용자에 의해 타입을 지정되는 것 ( 타입을 일반화한다 ) 을 의미합니다.
제네릭의 특징
- 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있다.
- 반환값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있다.
- 잘못된 타입이 입력되는 것을 컴파일 단계에서 방지할 수 있다.
- 재사용성이 높다.
제네릭 사용방법
타입 | 설명 |
<T> | Type |
<E> | Element |
<K> | Key |
<V> | Value |
이 표현식은 관례적으로 사용되고 있습니다. 반드시 일치해야할 필요도 없고 한 글자일 필요도 없습니다.
하지만 개발은 혼자하는것이 아니기에...
public interface Generic <T> { ... }
public class Generic <T> { ... }
public class Generic <T, K> { ... }
클래스와 인터페이스는 이렇게 선언하면 됩니다.
이번에는 List와 같은 클래스를 하나 만들어 보겠습니다.
제네릭 클래스
public class Generic <T> {
private final List<T> list = new ArrayList<>();
public void add(T value) {
list.add(value);
}
public void remove(T value) {
list.remove(value);
}
public T get(int index) {
return list.get(index);
}
}
public static void main(String[] args) {
Generic<String> generic = new Generic<>();
String test = "제네릭";
generic.add(test);
generic.remove(test);
int size = generic.size();
System.out.println(size); // 0
}
만약 String 이 아닌 타입이 입력된다면?
public static void main(String[] args) {
Generic<String> generic = new Generic<>();
int test = 1;
generic.add(test); // 컴파일 에러!
generic.remove(test); // 컴파일 에러!
int size = generic.size();
System.out.println(size);
}
컴파일 과정에서 오류를 방지할 수 있습니다.
제네릭 메서드
// [접근제어자] <제네릭타입> [반환타입] [변수명] ( [제네릭타입] 매개변수명 )
public <T> T getMethod(T value) { ... }
와일드 카드 < ? >
위에서의 제네릭에서는 타입을 제한하지 않았습니다. 와일드카드는 타입의 제한을 둘 수 있습니다.
<K extends T> { ... } // T, T의 자식 타입만 가능
<K super T> { ... } // T, T의 부모 타입만 가능
<? extends T> { ... } // T, T의 자식 타입만 가능
<? super T> { ... } // T, T의 부모 타입만 가능
여기서 K extends T와 ? extends T 는 차이가 있습니다.
K는 타입이 지정이 되지만 ?는 타입이 지정되지 않습니다.
여기서 주의점은 와일드카드는 클래스에 사용할 수 없다는 것입니다. 클래스에서는 타입을 <K extends T>와 같이 지정해주어야합니다.
public class Parent{
public void call() {
System.out.println("Parent Call");
}
}
public class Children extends Parent{
@Override
public void call() {
System.out.println("Children Call");
}
}
public class Main {
public static void main(String[] args) {
List<Parent> list = new ArrayList<>();
list.add(new Parent());
list.add(new Children());
listCall(list);
}
private static void listCall(List<? extends Parent> list) {
for (Parent parent : list) {
parent.call();
}
// Parent Call 출력
// Children Call 출력
}
}
'Language > JAVA' 카테고리의 다른 글
[JAVA] String의 불변성(immutability) (0) | 2024.09.23 |
---|---|
[JAVA] 함수형 인터페이스에 대해서 알아보자 (0) | 2024.09.15 |
[JAVA] Collection List를 최적화해보자 (0) | 2024.03.18 |
[JAVA] 직렬화(Serialization)와 역직렬화(Deserialization) (0) | 2024.02.14 |
[JAVA] 정규식 Regular Expression (0) | 2024.01.02 |