이번 강의에서는 제네릭 타입에서 사용하는 와일드카드(?)와 상한/하한 제한(extends, super)을
수강 등록 시스템을 예로 들어 실습합니다.
registerCourse1, registerCourse2, registerCourse3 각각은 등록 가능한 대상의 타입을 다르게 제한하고 있으며,
이를 통해 유연하지만 안전한 타입 필터링이 가능해집니다.
📌 예제 코드 요약
📦 클래스 구조
class Person {}
class Worker extends Person {}
class Student extends Person {}
class HighStudent extends Student {}
class MiddleStudent extends Student {}
📦 Applicant 클래스
public class Applicant<T> {
public T kind;
public Applicant(T kind) {
this.kind = kind;
}
}
📦 Course 클래스 – 제네릭 메서드 정의
public class Course {
public static void registerCourse1(Applicant<?> applicant) {
System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course1을 등록함.");
}
public static void registerCourse2(Applicant<? extends Student> applicant) {
System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course2을 등록함.");
}
public static void registerCourse3(Applicant<? super Worker> applicant) {
System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course3을 등록함.");
}
}
✅ 메인 실행 예제
public class GenericExample {
public static void main(String[] args) {
// 모든 사람이 수강 가능한 일반 강좌
Course.registerCourse1(new Applicant<>(new Person()));
Course.registerCourse1(new Applicant<>(new Worker()));
Course.registerCourse1(new Applicant<>(new Student()));
Course.registerCourse1(new Applicant<>(new HighStudent()));
Course.registerCourse1(new Applicant<>(new MiddleStudent()));
System.out.println();
// 학생만 수강 가능한 강좌
Course.registerCourse2(new Applicant<>(new Student()));
Course.registerCourse2(new Applicant<>(new HighStudent()));
Course.registerCourse2(new Applicant<>(new MiddleStudent()));
System.out.println();
// 근로자 또는 그 상위 클래스만 수강 가능한 강좌
Course.registerCourse3(new Applicant<>(new Person()));
Course.registerCourse3(new Applicant<>(new Worker()));
}
}
💻 실행 결과
Person이(가) Course1을 등록함.
Worker이(가) Course1을 등록함.
Student이(가) Course1을 등록함.
HighStudent이(가) Course1을 등록함.
MiddleStudent이(가) Course1을 등록함.
Student이(가) Course2을 등록함.
HighStudent이(가) Course2을 등록함.
MiddleStudent이(가) Course2을 등록함.
Person이(가) Course3을 등록함.
Worker이(가) Course3을 등록함.
💬 코드 설명
🔹 Applicant<?>
- registerCourse1은 모든 타입의 지원자 허용
- 와일드카드 <?>는 타입 제한 없이 모든 객체 허용함
🔹 Applicant<? extends Student>
- registerCourse2는 Student와 그 자식 클래스만 허용
- 즉, Student, HighStudent, MiddleStudent만 수강 가능
- Person, Worker는 Student의 하위 클래스가 아니므로 불가
🔹 Applicant<? super Worker>
- registerCourse3는 Worker 또는 그 상위 클래스만 허용
- 즉, Worker, Person은 가능
- Student 및 그 하위 클래스는 불가 (상위 타입 아님)
💡 포인트 정리
선언 형태 |
의미 |
<?> |
모든 타입 허용 |
<? extends T> |
T와 그 자식들만 허용 (상한 제한) |
<? super T> |
T와 그 부모들만 허용 (하한 제한) |
- extends는 데이터를 꺼낼 때(read) 적합
- super는 데이터를 넣을 때(write) 적합
- 제한을 통해 타입 안전성과 코드 유연성을 동시에 확보할 수 있음
📌 정리하자면, 와일드카드와 extends, super 제한을 활용하면
"누가 수강할 수 있는가?" 같은 조건을 제네릭으로 명확하게 표현할 수 있습니다.
이는 컬렉션, API 설계, 프레임워크 개발 등에서 가장 자주 쓰이는 제네릭 패턴 중 하나입니다.