*** 이 개념은 "이것이 자바다. 신용권의 Java 프로그래밍 정복" 을 보고 정리한 것입니다. ***
채팅을 구현하려고 TCP, socket 등을 공부하다가 이상한 길로 새어
제네릭(Generic)이란 개념을 보게 되었다.
이전에 개발하면서 계속 써왔던 것인데, 이게 제네릭인줄은 이번에 처음 알았다.
그냥 많이 봤던 걸 예시로 들어주면
Hashmap<String, String> hashmap = new Hashmap<>();
이런 거다. 여기서 어떤게 제네릭이냐면 다이아몬드 연산자 <> 로 표현된 부분이다.
그렇다면 제네릭은 왜 사용하는가 ?
1. 타입 에러를 강하게 체크한다고 함.. 나중에 실행중에 타입 에러가 뜨는걸 막기 위해 컴파일 할때 부터 강하게 타입체크를 함
2. 타입 변환(Casting)을 제거한다고 함.. 비제네릭 코드는 타입 변환이 필요한 경우가 많은데, 제네릭 코드는 이걸 막아준다고 함.
** 형변환은 많을 수록 프로그램 성능에 좋지 못하다. **
예를 들어
List list = new ArrayList();
list.add("test");
String str = (String) list.get(0);
// 리스트에서 값을 뽑아 String 변수로 줄 때, (String) 이 붙어 타입변환이 일어남
이와 반면에 제네릭 코드를 사용하면
List<String> list = new ArrayList<String>();
list.add("test");
String str = list.get(0);
// 타입 변환이 필요 없음.
//참고로 자바7 부터는 <> 연산자만 사용해도 타입을 자동으로 유추해준다.
//위 코드의 첫번 째 줄을 아래처럼 써도 된다는 뜻.
List<String> list = new ArrayList<>();
이런 식으로 사용이 가능해진다는 것이다.
"제네릭 타입"이란 타입을 파라미터로 가지는 클래스와 인터페이스를 말한다.
public class 클래스이름<T> {...}
public interface 인터페이스이름<T> {...}
// T 에는 변수명과 동일한 규칙에 따라 작성할 수 있지만, 보통은 영대문자 1자로 작성한다.
이렇게 사용하는 이유는 위에서 언급했던 것 처럼.. 타입의 변환을 줄이기 위해서다.
가령
public class test{
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
이러한 클래스가 있다고 치자. 이 클래스로
Test test = new Test();
이렇게 객체를 만들어서 사용한다면
String 값을 get 하거나 set 해줄 때, Object <-> String 형 변환이 일어나고
Int 값을 get/set 해줄 땐, Object <-> Int 형 변환이 일어난다.
따라서 형변환을 최소화 하려면
public class test<T>{
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
이런 식으로 클래스를 만들어 주는 것이다. 그리고
Test<String> test = new Test<>();
Test<Integer> test1 = new Test<>();
이런 식으로 객체를 만들어 준다면.. test, test1 객체에 get, set 해줄 때 형변환 해줄 수요가 줄어든다.
(물론 코딩을 하다보면 이보다 많은 변수를 가진 클래스가 나오니 잘 써야하겠지만..)
더 발전하면,
처음에 보여준
Hashmap<String, String> hashmap = new Hashmap<>();
이건 멀티 타입 파라미터라고 하며, 보는 것처럼 제네릭 타입을 두 개 이상 사용할 수 있다. (컴마로 구분)
제네릭 메소드도 있다. 많이 사용할 것 같진 않아서 있다는 정도로만 기억하고 필요할 때 찾아보자.
제한된 타입 파라미터
<T extends 최상위타입> 이런 식으로 표현하는데.. 예를 들어 "최상위타입"에 Number가 들어가면
그 타입으로는 Number를 포함한 하위 타입(Byte, Short, Integer, Long, Double) 등이 자유롭게 들어올 수 있다는 것이다.
와일드카드 타입 <?> , <? extends ...> , <? super ...>
구체적인 타입을 지정하기 보다.. 와일드카드처럼 범위가 넓게 쓰겠다는 것이다.
<?> 는 모든 클래스나 인터페이스 타입이 올 수 있다.
<? extends ...> 는 상속처럼 ... 에 명시된 클래스와 자식 클래스를 사용할 수 있다.
<? super ...> 는 ...에 명시된 클래스와 그 부모 클래스를 사용할 수 있다.
제네릭 타입의 상속과 구현은 필요할 때 찾아보자.
기본적으로는 상속 관계에서 제네릭 타입도 <T> 상속받고 한다는 개념이다.
'개발 > 자바' 카테고리의 다른 글
쓰레드 (Thread) (0) | 2020.05.22 |
---|---|
인터페이스와 추상클래스 - Interface and Abstract Class (0) | 2020.05.22 |
클래스 (Class) (0) | 2020.05.21 |
JavaFX (0) | 2020.05.17 |
자바 (람다식, Lambda Expression) (0) | 2020.05.08 |
댓글