제네릭 2장

  1. 이왕이면 제네릭 타입으로 만들라
  2. 이왕이면 제네릭 메서드로 만들라
  3. 한정적 와일드 카드를 사용해 API 유연성을 높여라

4. 이왕이면 제네릭 타입으로 만들라

Object기반 스텍을 제네릭 스택으로 바꾸어보자

Onject Stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package gege;

import java.util.Arrays;
import java.util.EmptyStackException;

public class TestStack {


private Object[] elements; // => E[] elements;


private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

public TestStack(){

elements = new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(Object e){
ensureCapacity();
elements[size++] = e;
}


public Object pop(){

if(size == 0)
throw new EmptyStackException();

Object result = elements[--size];
elements[size] = null;
return result;
}

public boolean isEmpty(){

return size == 0;
}

private void ensureCapacity() {
if(elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);

}
}

–> 변환 to 제네릭 기반 스텍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package gege;

import java.util.Arrays;
import java.util.EmptyStackException;

public class TestStackVersionUp<E> {


private E[] elements; // => E[] elements;


private int size = 0;
private static final int DEFAULT_INITIAL_CAPACITY = 16;

@SuppressWarnings("unchecked") //
public TestStackVersionUp(){

elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY];
}

public void push(E e){ //변경
ensureCapacity();
elements[size++] = e;
}


public E pop(){ // 변경

if(size == 0)
throw new EmptyStackException();

E result = elements[--size]; // 변경
elements[size] = null;
return result;
}

public boolean isEmpty(){

return size == 0;
}

private void ensureCapacity() {
if(elements.length == size)
elements = Arrays.copyOf(elements, 2 * size + 1);

}
}

대다수의 제네릭 타입은 타입 매개변수에 아무런 제약을 두지 않는다. TestStackVersionUp, TestStackVersionUp<List> 등 어떤 참조 타입으로도 TestStackVersionUp을 만들수 있다. 단 기본 타입은 사용할수 없다.

이펙티브자바 3판 5장 제네릭 참고! (잊지 않기 위해 블로그에 올립니다)

5. 이왕이면 제네릭 메서드로 만들라

클래스와 마찬가지로, 메서드 또한 제네릭으로 만들 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package gege;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {

public static void main(String[] args) {


List<String> groupOne = Arrays.asList("가", "나", "다");
List<String> groupTwo = Arrays.asList("A", "B", "C");

List<String> unionGroups = unionGroup(groupOne, groupTwo);


System.out.println(unionGroups.toString());

System.out.println(unionGroupVersionUp(groupOne,groupTwo).toString());
}


//제네릭 미적용
private static List<String> unionGroup(List<String> groupOne, List<String> groupTwo) {

List<String> unions = new ArrayList<>(groupOne);

unions.addAll(groupTwo);

return unions;
}


//제네릭 적용
private static <E> List<E> unionGroupVersionUp(List<E> groupOne, List<E> groupTwo) {

List<E> unions = new ArrayList<>(groupOne);

unions.addAll(groupTwo);

return unions;
}


}

unionGroup 메서드는 2개의 매개변수, 반환되는 타입 한개의 타입이 모두 같아야 한다!. 때때로는 불변 객체를 여러 타입으로 활용할수 있게 만들어야 한다. 제네릭은 런타임에 타입 정보가 소거 되므로 하나의 객체를 어떤 타입으로든 매개변수화할수 있다.

그렇다면 방법은? 요청한 타입 매개 변수에 맞게 매번 그 객체의 타입을 바꿔주는 정적 팩토리를 만들어야 한다. 이를 제네릭 싱글턴 factory라 한다.
Collections.reverseOrder, Collections.emptySet이 좋은 예제이다.

1
@SuppressWarnings("unchecked") public static <T> Comparator<T> reverseOrder() { return (Comparator<T>) ReverseComparator.REVERSE_ORDER; }

6. 한정적 와일드 카드를 사용해 API 유연성을 높여라

유연성을 극대화하려면 원소의 생산자나 소비자용 입력 매개변수에 와일드카드 타입을 사용하라. 한편 입력 매개변수가 생산자와 소비자 역할을 동시에 한다면 와일드카드 타입을 써도 좋을게 없다.

매개변수화 타입 T가 생산자라면 <? extends T>를 사용하고 소비자라면 <? super T> 를 사용하라.

솔찍히 이해가 안간다.. 머리가 아프다.. 나는 개발자가 맞는것인가…… 여기서 ..제네릭은 멈추고… 나중에 다시 읽자……

이펙티브자바 3판 5장 제네릭 참고! (잊지 않기 위해 블로그에 올립니다)