- 제네릭스란?
- class 클래스명<T>, interface 인터페이스명<T>, T 변수명, T 메소드명()
- 저장되는 요소를 제네릭타입<T> 으로 제한 (제네릭 타입과 일치하는 객체만 저장)
- Object를 사용하면, 자바의 모든 객체를 받을 수 있음
- 객체의 타입 안정성을 높인다.
- 타입체크와 형변환을 생략할수있으므로 코드가 간결해진다. →프로그램 성능 향상
List list=new ArrayList();
list.add("hello");
String str=(String)list.get(0); //타입변환 해야함
List<String> list=new ArrayList<String>(); //String객체만 저장할수있는 list 생성
list.add("hello");
String str=list.get(0); //타입변환할 필요 없음
- 타입변수<T>
- 제네릭클래스를 작성할때, Object타입(일반클래스) 대신 타입변수<T>를 선언해서 사용 (모두 타입파라미터T로 대체 → 매개변수화된 타입)
- 객체 생성 시, 타입변수 <T> 대신 실제 타입을 대입 (타입변수에 대입은 인스턴스별로 다르게 가능)
- 다형성
- 참조변수와 생성자의 대입된 타입은 일치해야한다. List<String> list=new ArrayList<String>();
- 제네릭클래스 간의 다형성은 성립 List<Tv> list = new ArrayList<Tv>(); //ok. ArrayList는 List의 자손
- 매개변수의 다형성도 성립 ArrayList<Product> list = new ArrayList<Product>(); list.add(new Tv()); //ok. Tv는 Product의 자손
- 다형성
- static멤버에는 타입변수를 사용할수없다.
- 타입변수로 배열 선언은 가능하지만(T타입의 배열 ok), 배열 생성할때는 타입변수 사용 불가 (new T[n]은 불가)
- 멀티타입파라미터: 여러개의 타입변수가 필요한 경우, 콤마를 구분자로 선언. class<K,V...>
- 제한된 제네릭클래스, 제한된 타입파라미터
- <T extends 상위타입>
- 타입파라미터T에 대입할수있는 타입을 제한
- 상위타입은 클래스 뿐 아니라 인터페이스도 가능
- 와일드카드 타입
- 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능
- ArrayList<? exends Product> list = new ArrayList<Tv>();
- 와일드카드는 다음 세가지형태로 사용할수있다
- <?>
- 제한없음: 모든 타입이 올수있다. <? extends Object>와 동일
- <? extends 상위타입>
- 상위클래스 제한: 상위타입과 그 자손들만 가능
- <? super 하위타입>
- 하위클래스 제한: 하위타입과 그 조상들만 가능
- <?>
- 메소드의 매개변수에 와일드카드를 사용할수있다.
- 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능
class Course<T> { ... }
void register(Course<?> c){...}
void registerStudent(Course<? extends Student> c){...}
void registerWorker(Course<? super Worker> c){...}
Course<Person> personCourse = new Course<Person>("일반인과정", 5);
/**매개변수의 다형성은 성립*/
personCourse.add(new Person("일반인"));
personCourse.add(new Worker("직장인")); //Worker는 Person의 자손
- 제네릭 메소드: 제네릭 타입이 선언된 메소드 (타입변수는 메소드 내에서만 유효)
- <T,...> 반환타입 메소드명(매개변수,...) { }
- 메소드를 호출할때마다, 다른 제네릭타입을 대입할수있게함
- 클래스의 타입매개변수와 메소드의 타입매개변수는 별개 (다른 타입변수)
- 메소드를 호출할때마다, 타입을 대입 (대부분 생략가능)
- 메소드를 호출할때 타입을 생략하지않을때는, 클래스이름 생략 불가
- Util.<Integer, String>compare(a,b); //ok
- Juicer.<Fruit>makeJuice(f); //ok
- <Fruit>makeJuice(f); //에러
- 메소드를 호출할때 타입을 생략하지않을때는, 클래스이름 생략 불가
- 제네릭타입의 형변환
- 와일드카드가 사용된 제네릭타입으로는 형변환 가능
- Box<Object> objBox = (Box<Object>)new Box<String>(); //에러. 형변환 불가능
- Box<? extends Object>
- 제네릭타입과 원시타입(일반클래스) 간의 형변환은 바람직하지않다. (경고 발생)
- 와일드카드가 사용된 제네릭타입으로는 형변환 가능
- 제네릭타입의 제거: 컴파일러는 제네릭타입을 제거하고, 필요한 곳에 형변환을 넣는다
- 제네릭 타입의 경계를 제거
- 제네릭타입 제거 후에 타입이 불일치하면, 형변환을 추가
- 와일드카드가 포함된 경우, 적절한 타입으로 형변환 추가
1.
class Box<T extends Fruit>{
void add(T t){...}
}
//제네릭타입의 제거
class Box{
void add(Fruit t){...}
}
2.
get(int i){
return list.get(i);
}
//제네릭타입의 제거
Fruit get(int i){
return (Fruit)list.get(i);
}
3.
static Juice mekeJuice(FruitBox<? extends Fruit> box){
String tmp="";
for (Fruit f:box.getList()){
tmp += f+"";
return new Juice(tmp);
}
//제네릭타입의 제거
static Juice mekeJuice(FruitBox box){
String tmp="";
Iterator it=box.getList().iterator();
while(it.hasNext()){
tmp+= (Fruit)it.next() +"";
}
return new Juice(tmp);
}
728x90
반응형
'Java Tutorial' 카테고리의 다른 글
[Java] 람다식 (0) | 2023.03.14 |
---|---|
[Java] Set컬렉션 (0) | 2023.02.19 |
[Java] List컬렉션 (0) | 2023.02.18 |
[Java] 컬렉션 프레임워크 (Collection Framework) (0) | 2023.02.16 |
[Java] 객체 지향 프로그래밍 (Object Oriented Programming) (0) | 2023.02.10 |