와일드 카드
일반적으로 지네릭스를 선언하면 대입된 타입이 일치해야 하는데, 와일드 카드를 사용하면 대입 변수가 불일치하여도 컴파일 오류가 발생하지 않는다.
대표적으로 아래와 같이 선언한다.
- <? extends Object obj> : obj와 그 자손들만 상속 가능 (상한적 제한)
- <? super Object obj> : obj와 그 조상들만 상속 가능(하한적 제한)
- <?> : 모든 Object 타입 가능, Object / E / T를 직접 선언한 것과 같음
1. <? extends Object obj> : 대입된 변수 obj와 그 자손들만 상속 가능
*plant2를 상속한 자손인 basil2와 rose만 지네릭스를 선언할 수 있다.
ArrayList<? extends plant2> arr = new ArrayList<plant2>();
ArrayList<? extends plant2> arr2 = new ArrayList<basil2>();
ArrayList<? extends plant2> arr3 = new ArrayList<rose>();
}
}
class nature{}
class plant2 extends nature{}
class basil2 extends plant2{}
class rose extends plant2{}
2. <? super Object obj> : 대입된 변수 obj와 그 조상들만 상속 가능
*plant2의 조상인 nature만 지네릭스를 선언할 수 있다.
ArrayList<? super plant2> arr4 = new ArrayList<nature>();
ArrayList<? super plant2> arr5 = new ArrayList<plant2>();
// ArrayList<? super plant2> arr6 = new ArrayList<basil2>();
}
}
class nature{}
class plant2 extends nature{}
class basil2 extends plant2{}
class rose extends plant2{}
3. <?> : 전부 선언가능
ArrayList<?> arr7 = new ArrayList<nature>();
}
}
class nature{}
class plant2 extends nature{}
class basil2 extends plant2{}
class rose extends plant2{}
지네릭스 형변환
지네릭스가 선언된 타입을 지네릭타입이라 하고 선언되지 않은 클래스 타입을 원시 타입이라 부른다.
원시타입을 지네릭타입으로 형변환이 가능할까?
컴파일오류는 발생하지 않지만 지네릭타입을 원시타입으로 형변환할 경우에는 지네릭타입에 어떤 타입이 들어갈 지 모르기 때문에 경고를 발생시킨다.
t = (test)ObjT; // 원시 타입 t에 지네릭타입 ObjT을 형변환 하여 대입 > 경고
ObjT = (test<Object>)t; //지네릭 타입 objT에 test<Objct>로 원시타입 t를 형변환 하여 대입 > 경고
따라서 형변환시에는 와일드 카드가 선언된 지네릭타입으로만 형변환한다.
아래 예시처럼 와일드카드가 Object를 상속한 모든 타입을 사용하는 것을 허용하므로 어떤 타입이 들어와도 컴파일 오류가 발생되지 않는다.
*형변환 생략 가능
test<? extends Object> t2 = (test<? extends Object>)new test();
test<? extends Object> t3 = new test();
// 위의 두개의 문장은 동일한 의미, 다만 지네릭스에 제한을 둠으로써 모든 타입을 받아올 수 있기 때문에 생략을 허용
// Object를 상속한 모든 변수를 허용함으로써 모든 대입 변수 허용
}
}
class test<T>{}
지네릭 타입 제거
컴파일러가 실행될 시 지네릭타입은 제거되고 컴파일러가 필요한 곳에 자동으로 형변환을 시킨다.
클래스의 지네릭스를 T 또는 E로 선언하고 컴파일러를 실행하면 T와 E가 Object로 자동으로 형변환된다.
- 아래의 주석과 같이 T가 제거되면서 Object로 변경됨
class Test<T>{
void add(T t) {
// void add(Object obj)
}
}
만약 지네릭스가 제한되어 있다면 어떤 타입으로 형변환이 될까?
만약 지네릭스가 제한되어있다면 그 제한된 class로 형변환이 되고 명확한 값이 출력될 때는 컴파일러가 자동으로 제한된 class로 형변환을 시켜준다.
class TestLimited<T extends Test>{
String add(T t) {
// void add(Test t)
return "형변환필요but생략";
// return (Test)"형변환필요but생략";
}
}
'Java > 자바의정석 기초편' 카테고리의 다른 글
자바의 정석 12장 (32일차) - 스레드 (0) | 2022.02.24 |
---|---|
자바의 정석 12장 (31일차) - 열거형 (enum) (0) | 2022.02.22 |
자바의 정석 12장 (30일차) - 지네릭스(Generics) & 타입 변수 & 제약 (0) | 2022.02.21 |
자바의 정석 11장 (30일차) - Collections 클래스 (0) | 2022.02.21 |
자바의 정석 11장 (30일차) - HashMap (0) | 2022.02.21 |