와일드카드(?) 타입이란?
제네릭 타입을 매개변수나 리턴타입으로 사용할 때 타입 파라미터를 제한할 목적
※ 비교
<T extends 상위 또는 인터페이스>는 제네릭 타입과 제네릭 메소드를 선언할 때 제한을 한다.
public static void registerCourse(Course<?> course{
public static void registerCourseStudent(Course<? extends Student> course{
public static void registerCourseWorks(Course<? super Worker> course{
와일드카드 타입의 세가지 형태
제네릭타입<?> : Unbounded WildCards(제한 없음)
타입 파라미터를 대치하는 구체적인 타입으로 모든 클래스나 인터페이스 타입이 올 수 있다.
public static void registerCourse(Course<?> course{
제네릭타입<? extends 상위타입> : Upper Bounded Wildcards ( 상위 클래스 제한 )
타입 파라미터를 대치하는 구체적인 타입으로 상위 타입이나 하위 타입만 올 수 있다.
public static void registerCourseStudent(Course<? extends Student> course{
exam ) E -> D -> C -> B -> A E가 D를 상속 -> D가 C를 상속 ->C가 B를 상속 .....
<? extends C> 라면 c, d, e 를 사용 할 수 있다.
제네릭타입<? super 하위타입> : Lower Bounded Wildcards ( 하위 클래스 제한 )
타입 파라미터를 대치하는 구체적인 타입으로 하위 타입이나 상위 타입이 올 수 있다.
public static void registerCourseWorks(Course<? super Worker> course{
exam ) E -> D -> C -> B -> A E가 D를 상속 -> D가 C를 상속 ->C가 B를 상속 .....
<? extends C> 라면 c, b, a 를 사용 할 수 있다.
Exam
수강코스를 만들고 수강 생을 수강코스에 넣는다?
만들 클래스들
수강코스 클래스
public class Course<T> {
private String 수강코스명;
private T[] 수강인원;
//외부에서 수강코스명과 인원수를 결정해서 만들어냄
public Course(String 수강코스명, int capacity) {
this.수강코스명 = 수강코스명;
//T가 결정이 안된상태에서 배열을 생성할수 없다.
//수강인원 = new T[capacity] (x)
수강인원 = (T[]) (new Object[capacity]);
}
public String get수강코스명() { return 수강코스명; }
public T[] get수강인원() { return 수강인원; }
public void add(T t) {
for (int i = 0; i < 수강인원.length; i++) {
if (수강인원[i] == null) {
수강인원[i] = t;
break;
}
}
}
}
Person클래스
public class Person {
public String name;
public Person(String name) {
this.name = name;
}
public String getName() { return name; }
@Override
public String toString() {
return name;
}
}
Student 클래스
public class Student extends Person {
public Student(String name) {
super(name);
}
}
HighStudent 클래스
public class HighStudent extends Student {
public HighStudent(String name) {
super(name);
}
}
Worker 클래스
public class Worker extends Person {
public Worker(String name) {
super(name);
}
}
메인 메서드
public class WildCardExample {
// 수강코스의 코슴이름과 수강중인 사람들을 보여주는 메서드들 * 메서드 타입 파라미터가 다름 *
static void registerCourse(Course<?> course) {
System.out.println("registerCourse()메서드의 [ " + course.get수강코스명() + " ] 수강생: " + Arrays.toString(course.get수강인원()));
}
// Student 상위 타입을 제한
static void registerCourseStudent(Course<? extends Student> course) {
System.out.println("registerCourseStudent()메서드의 [ " + course.get수강코스명() + " ] 수강생: " + Arrays.toString(course.get수강인원()));
}
// Worker 하위 타입을 제한
static void registerCourseWorker(Course<? super Worker> course) {
System.out.println("registerCourseWorker()메서드의 [ " + course.get수강코스명() + " ] 수강생: " + Arrays.toString(course.get수강인원()));
}
public static void main(String[] args) {
Course<Person> personCourse = new Course<Person>("사람이면 가능한 과정", 5);
personCourse.add(new Person("일반인"));
personCourse.add(new Worker("직장인"));
personCourse.add(new Student("학생"));
personCourse.add(new HighStudent("고등학생"));
Course<Worker> workerCourse = new Course<>("직장인 과정", 5);
workerCourse.add(new Worker("직장인"));
workerCourse.add(new Worker("직장인"));
//workerCourse.add(new Student("학생")); 불가능
Course<Student> studentCourse = new Course<>("학생 과정", 5);
studentCourse.add(new HighStudent("고등학생"));
studentCourse.add(new Student("학생"));
//studentCourse.add(new Person("일반인")); 불가능
Course<HighStudent> highStudentCourse = new Course<>("고등학생 과정", 5);
highStudentCourse.add(new HighStudent("고등학생"));
//highStudentCourse.add(new Student("학생")); 불가능
registerCourse(personCourse);
registerCourse(workerCourse);
registerCourse(studentCourse);
registerCourse(highStudentCourse);
//상위 타입을 제한했으므로 하위타입인 highStudentCourse 와 studentCourse 사용가능
// registerCourseStudent(personCourse); 불가능
// registerCourseStudent(workerCourse); 불가능
registerCourseStudent(studentCourse);
registerCourseStudent(highStudentCourse);
//하위 타입을 제한했으므로 상위타입인 PersonCourse 와 workerCourse 사용가능
registerCourseWorker(personCourse);
registerCourseWorker(workerCourse);
// registerCourseWorker(studentCourse); 불가능
// registerCourseWorker(highStudentCourse); 불가능
}
}
실행 결과