자바 1.5이전 컬렉션
private final Collection stamps = ...;
// 엉뚱한 자료형을 넣어도 컴파일 시 문제가 없었다.
stamps.add(new Coin(...));
for(Iterator i = stamps.iterator() ; i.hasNext(); ){
Stamp s = (Stamp) i.next(); //ClassCastException 예외 발생
...//우표 작업
}
ClassCastException이 발생하게 되면 stamps컬렉션에 엉뚱한 객체를 넣는 코드를 찾아야 한다.
// 형인자 컬렉션 자료형 - 형 안전성 확보
private final Collection<Stamp> stamps = ...;
위와 같이 선언하면 stamps 컬렉션에 Stamp 객체만 넣을 수 있다는 것을 이해할 수 있으며 실제로 Stamp 객체만 삽입되도록 한다.
게다가 원소를 꺼낼 때 형변환을 하지 않아도 된다.
- for-each던 for문이건 마찬가지 이다.
List와 같은 무인자 자료형을 사용하면 형 안전성을 잃게 되지만, List<Object>와 같은 형인자 자료형을 쓰면 그렇지 않다.
// 실행 도중에 오류를 일으키는 무인자 자료형 사용 예
public static void main(String[] args){
List<String> strings = new ArrayList<String>();
unsafeAdd(strings, new Integer(42));
String s = strings.get(0); // 컴파일러가 자동으로 형 변환
}
private static void unsafeAdd(List list, Object o){
list.add(o);
}
//// 결과 : 컴파일은 잘되지만 무인자 자료형 list를 썻기 때문에 경고가 뜬다.
waring : unchecked call to add(E) in raw type List
list.add(o);
실제로 돌려보면 string.get(0)의 실행 결과를 String으로 변환하려 하기 때문에 ClassCastException예외가 발생한다.
버전 1.5부터 자바는 비한정적 와일드카드 자료형을 제공한다.
- 제네릭 자료형을 쓰고 싶으나 실제 형인자가 무엇인지는 모르거나 신경쓰고싶지 않을 때는 형인자로 ?를 쓰면 된다.
- Set<E>에 대한 비한정적 와일드 카드 자료형은 Set<?>이다.
//비한정적 와일드 카드 자료형 - 형 안전성과 유연성 만족
static int numElementsIncommon(Set<?> s1, Set<?> s2){
int result = 0;
for (Object o1 :s1){
if(s2.contains(o1))
result++;
return result;
}
Set<?>과 Set의 차이는 무엇인가?
- 와일드 카드 자료형은 안전하지만 무인자 자료형은 그렇지 않다.
- 무인자 자료형은 아무 객체나 넣을 수 있어서 컬릭션 자료형 불변식이 깨진다.
- 그러나 Collection<?>에는 null이외에 어떤 원소도 넣을 수 없다.
ㄴ어떤 자료형의 객체를 담는 컬렉션인지 알 방법이 없기 때문이다.
새로운 코드에는 무인자 자료형을 쓰면 안된다고 했지만 예외가 두가지 있다.
1) 클래스 리터럴에는 반드시 무인자 자료형을 사용해야 한다.
- 자바 표준에 따르면 클래스 리터럴에는 형인자 자료형을 쓸 수 없다.
ㄴ 배열 자료형이나 기본자료형은 쓸수 있다.
ㄴex) List.class, String[].class, int.class...
- instanceof 연산자는 비한정적 와일드 카드 자료형 이외의 형인자 자료형에 적용할 수 없다.
// instancof 연산자에는 무인자 자료형을 써도 OK
if( o instanceof Set ){ //무인자 자료형
Set<?> m = (Set<?>) o; //와일드 카드 자료형
....
}
* o가 Set객체라는것이 확실해진 다음에는 와일드 카드 자료형 Set<?>로 형변환 해야하는 것에 주의하자.
요약
- 무인자 자료형을 쓰면 프로그램 실행 도중에 예외가 발생할 수 있으므로, 새로 만드는 코드에는 무인자 자료형을 쓰지 말아야 한다.
- 무인자 자료형을 제네릭 도입 전 코드 호환성을 유지하기 위해 제공하는것에 불과하다.
- Set<Object> 는 어떤 자료형의 객체도 담을 수 있는 집합의 자료형
- Set<?>는 모종의 자료형 객체만 담을 수 있는 집합의 자료형
- Set<Object>와 Set<?>는 안전하지만 Set은 안전하지 않다.
용어
|
예시
|
형인자 자료형
|
List<String>
|
실 형인자
|
String
|
제네릭 자료형
|
List<E>
|
형식 형인자
|
E
|
비한정적 와일드카드 자료형
|
List<?>
|
무인자 자료형
|
List
|
한정적 형인자
|
<E extends Number>
|
재귀적 형 한정
|
<T extends Comparable<T>>
|
한정적 와일드카드 자료형
|
List<? extends Number>
|
제네릭 메서드
|
static <E> List<E> asList(E[] a)
|
자료형 토큰
|
String.class
|
'IT > Programming' 카테고리의 다른 글
<Effective Java> RULE 21 전략을 표현하고 싶을 때는 함수 객체를 사용하라 (0) | 2023.04.27 |
---|---|
<Effective Java> RULE 22 멤버클래스는 가능하면 static으로 선언하라 (0) | 2023.04.27 |
<Effective Java> RULE 24 무점검 경고(unchecked warining)을 제거하라 (0) | 2023.04.27 |
<Effective Java> RULE 25 배열대신 리스트를 써라 (0) | 2023.04.27 |
<Effective Java> RULE 26 가능하면 제네릭 자료형으로 만들 것 (0) | 2023.04.27 |