[자바 라이브 스터디] 12주차 - 제네릭
•
목표) 자바의 제네릭에 대해 학습하세요.
1. 제네릭 사용법
•
정의) 컴파일 시의 타입 체크를 해줘서 메서드나 클래스가 다양한 타입의 객체 다룰 수 있게 해주는 기능
•
특징)
◦
타입 안정성을 제공함
◦
타입체크와 형변환 생략 가능해져 코드 간결해짐
◦
static 멤버에 T 사용 불가(T가 인스턴스 변수로 간주되기 때문)
◦
instanceof 연산자와 new 연산자의 피연산자로 T 사용 불가(컴파일 시점에 T가 뭔지 정확히 알아야 하기 때문)
•
사용) UserUtils<T> 와 같이 선언해 제네릭 클래스를 만들어두고, UserUtils<User> 와 같이 제네릭 타입을 호출해 사용함
•
예시)
1.
제네릭 타입을 클래스에 선언
•
클래스 옆에 <T>를 붙이고 Object 타입들을 T 타입으로 변경
◦
적용 전
class UserUtils; {
Object user;
void setUser(Object user) { this.user = user; }
Object getUser() { return user; }
}
Java
복사
◦
적용 후 → 제네릭 클래스 UserUtils<T>
class UserUtils<T>; {
T user;
void setUser(T user) { this.user = user; }
T getUser() { return user; }
}
Java
복사
2.
제네릭 클래스의 객체 생성
•
참조변수와 생성자에 T 타입 대신에 사용할 실제 타입을 지정
Teacher teacher = new Teacher();
UserUtils<Teacher> userUtils= new UserUtils<Teacher>();
userUtils.setUser(new Object()); //에러
userUtils.setUser(teacher);
Teacher newTeacher = (Teacher)userUtils.getUser();
Java
복사
◦
JDK 1.7부터 UserUtils<Teacher> userUtils= new UserUtils<>();도 가능
•
제네릭 도입 전 코드와의 호환 위해 아래도 허용은 하지만 경고 발생함 (지양하자)
Teacher teacher = new Teacher();
UserUtils userUtils = new UserUtils();
userUtils.setUser(new Object()); // 경고
userUtils.setUser(teacher); // 경고
Java
복사
•
만일 경고 안 뜨게 하고 싶다면, Object 타입으로라도 지정해주면 됨
Teacher teacher = new Teacher();
UserUtils<Object> userUtils = new UserUtils<Object>();
userUtils.setUser(new Object());
userUtils.setUser(teacher);
Java
복사
2. 제네릭 주요 개념 (바운디드 타입, 와일드 카드)
•
바운디드 타입
◦
정의) 제네릭 타입에서 타입 인자로 사용할 수 있는 타입을 제한하려는 경우 바운디드 타입 매개변수를 선언해 사용
◦
사용) 타입 매개변수 이름(T), extends 키워드, 상위 바운드를 나열
▪
UserUtils<T extends User> 와 같이 사용하면 User의 자손들만 담을 수 있게 제한 가능
▪
UserUtils<T extends Speakable>의 Speakable가 인터페이스여도 마찬가지로 extends를 사용함
▪
UserUtils<T extends User & Speakable>과 같이 사용하면 User의 자손이면서 Speakable을 구현한 클래스만 타입 매개변수 T에 대입할 수 있음 (순서는 인터페이스보다 클래스가 먼저 와야 함)
•
와일드 카드
◦
정의) 제네릭 타입이 달라도 오버로딩 성립하게 하려는 경우, 모든 타입을 대신할 수 있는 와일드카드 타입 사용
◦
사용)
▪
UserUtils<? extends User> 와 같이 사용하면 User의 자손들만 담을 수 있게 제한 가능
▪
UserUtils<? super User>와 같이 사용하면 User의 조상들만 담을 수 있게 제한 가능
▪
UserUtils<?>와 같이 사용하면 모든 타입이 가능. UserUtils<? extends Object>와 동일
3. 제네릭 메소드 만들기
•
정의) 메서드 선언부에 제네릭 타입이 선언된 메서드
•
특징)
◦
제네릭 타입의 선언 위치는 반환 타입 바로 앞임
◦
제네릭 메서드는 제네릭 클래스가 아닌 클래스에도 정의 가능
•
사용)
◦
적용 전)
static Lecture makeLecture(UserUtils<? extends User> userUtils) {
return new Lecture();
}
Java
복사
◦
적용 후)
static <T extends User> Lecture makeLecture(UserUtils<T> userUtils) {
return new Lecture();
}
Java
복사
4. Erasure
•
정의) 컴파일러가 제네릭 타입 이용해서 소스파일 체크하고 필요한 곳에 형변환 넣어주어 결국 컴파일 후 원시 타입으로 바뀜
•
과정)
◦
제네릭 타입의 경계 제거
▪
적용 전)
class UserUtils<T extends User> {
void add(T t) { ... }
}
Java
복사
▪
적용 후)
class UserUtils {
void add(User user) { ... }
}
Java
복사
◦
제네릭 타입 제거한 후 타입 일치하지 않으면 형변환 추가
▪
적용 전)
T get (int i) { return list.get(i); }
Java
복사
▪
적용 후)
User get (int i) { return (User)list.get(i); }
Java
복사