1.1 제네릭이란?
- 컴파일 시 타입을 체크해주는 기능이다.
- 형변환의 번거러움을 줄여주고, 타입을 체크해주므로 코드가 간결해진다.
즉, 데이터 형식에 의존하지 않고, 하나의 값이 다른 데이터 타입들을 가질 수 있도록 하는 방법이다.
1.2 활용
만약, 어떤 자료구조를 만들어 배포하려고할 때 String, Integer 모두 지원하고 싶다고 가정해보자.
이 때 String, Integer에 대한 클래스 모두 만드는 것은 비효율적이다. 이를 해결하기 위해 제네릭을 사용한다.
아래 타입들이 많이 사용된다. (암묵적인 규칙일 뿐 반드시 따라야하는 것은 아니다.)
타입 | 설명 |
<T> | Type |
<E> | Element |
<K> | Key |
<V> | Value |
<N> | Number |
1.3 사용방법
# Object 객체 사용
class Box {
Object item;
void setItem(Object item) { this.item=item; }
Object getItem() { return item; }
}
# 제네릭 사용
class Box<T> {
T item;
void setItem(T item) { this.item=item; }
T getItem() { return item; }
}
1.4 제약사항
1) static 멤버에는 타입 변수 T를 사용할 수 없다.
ex.
class Box<T>{
static T item; // 에러
static int compare (T t1, T t2){} // 에러
}
2) 제네릭 타입의 배열 T[]를 생성하는 것은 허용되지 않는다.
ex.
class Box<T> {
T[] itemArr;
T[] toArray() {
T[] tempArr=new T[itemArr.length]; // 에러
return tmpArr;
}
}
3) 참조변수와 생성자에 대입된 타입이 일치해야한다.
Box<Apple> appleBox = new Box<Apple>();
Box<Apple> appleBox = new Box<Grape>(); //에러
4) 두 지네릭 클래스가 상속관계이고, 대입된 타입이 일치하는것은 무관하다.
Box<Apple> appleBox = new FruitBox<Apple>();
1.4 제네릭 클래스 제한하기
class FruitBox<T extends Fruit> { // Fruit의 자손만 타입으로 지정 가능하다는 의미
ArrayList<T> list = new ArrayList<T> ();
void add(T item) {list.add(item);}
}
* 주의: 인터페이스의 경우에도 implements가 아닌 extends를 사용한다.
1.5 와일드 카드 '?'
자바에서 타입 파라미터간에는 상/하위 관계가 없고, raw-type간에 상-하위 관계가 존재한다.
예를 들어 Number는 Integer에 상위이고, List<Integer>은 ArrayList<Integer>의 상위이지만, List<Number>, List<Integer>은 상 하위 관계라고 볼 수 없다.
조금 더 구체적인 예를 보면
List<String> stringList = new ArrayList<>();
List<Object> objectList = stringList;
objectList.add(123);
String s = stringList.get(0);
objectList에 stringList가 수행된 후 123이라는 수를 넣는 것이니, String 타입 변수에 Integer 타입 값을 넣는게 가능해져버린다.
그러므로 List<Object> 타입 변수에 List<String> 타입 변수를 넣을 수 없다.
(실제로 컴파일 오류가 난다.)
그래서 어떤 컬레션이든 받아서 출력하는 메소드를 만들기 위해 ?(와일드 카드) 개념이 등장하였다.
static void printCollection(Collection <Object> c) {
for (Object e:c){
System.out.println(e);
}
}
public static void main(String [] args) {
Collection<String> c = new ArrayList<>();
c.add("hi");
printCollection(c);
// 메소드 파라미터 타입은 Collection<Object>인데, String 타입을 받고 있기 때문에 오류 발생
}
static void pringCollection(Collection<?> c)
로 바꿔주면 오류가 고쳐진다.
추가로
static void printCollection(Collection<? extends Number> c){
for ( Number e:c){
System.out.println(e);
}
}
public static void main(String[] args){
Collection<Integer> c = new ArrayList<>();
c.add(123);
printCollection(c);
}
extents를 사용하면 number을 상속한 어떤 것만 사용 가능하도록 제한 할 수 있다.
참고)
https://st-lab.tistory.com/153
'Backend Study > Java' 카테고리의 다른 글
[JAVA] 힙 메모리 사용률 (0) | 2023.02.09 |
---|---|
[JAVA] static 변수와 메서드 (0) | 2023.02.06 |
[JAVA]링크드리스트로 큐 구현하기 (Queue) (0) | 2023.02.06 |
[JAVA] 오버로딩 vs 오버라이딩 (0) | 2023.02.02 |
[JAVA] JVM, JRE, JDK 차이 (0) | 2023.01.27 |