제한된 타입 파라미터와 와일드카드 타입

1. 제한된 타입 파라미터

  • T extends 상위타입(인터페이스 가능, 이경우에도 extends 키워드 사용)
  • 타입 파라미터에 지정되는 구체적인 타입은 사위 타입이거나 상위 타입의 하위 또는 구현클래스만 가능
  • 메소드내에서 타입 파라미터 변수를 가지고 사용가능한 것은 상위 타입의 필드와 메소드로 제한

2. 와일드카드 타입

  • <?> : Unbounded Wildcards (제한 없음)
    • 모든 클래스나 인터페이스가 올 수 있음
  • <? extends T> Upper Bounded Wildcards (상위 클래스 제한)
    • T 타입이나 T의 하위타입만 올 수 있음
  • <? super T> Lower Bounded Wildcards (하위 클래스 제한)
    • T 타입이나 T의 상위타입만 올 수 있음
// 예제 1-1. Coures.java
package com.jremind.exam04;

public class Course<T> {
	private String name;
	private T[] students;

	public Course(String name, int capacity) {
		this.name = name;
		students = (T[])(new Object[capacity]); //T타입으로 강제변환
	}

	public String getName() {
		return name;
	}

	public T[] getStudents() {
		return students;
	}
	public void add(T t) {
		for(int i=0; i<students.length; i++) {
			if(students[i] == null) {
				students[i] = t;
				break;
			}
		}
	}
}
// 예제 1-2. Person.java
package com.jremind.exam04;

public class Person {
	private String name;

	public Person(String name) {
		this.name = name;
	}
}
// 예제 1-3. Worker.java
package com.jremind.exam04;

public class Worker extends Person{
	public Worker(String name) {
		super(name);
	}
}
// 예제 1-4. Student.java
package com.jremind.exam04;

public class Student extends Person{
	public Student(String name) {
		super(name);
	}
}
// 예제 1-5. GraduateStudent.java
package com.jremind.exam04;

public class GraduateStudent extends Student{
	public GraduateStudent(String name) {
		super(name);
	}
}
// 예제 1-6. CourseMain.java
package com.jremind.exam04;

import java.util.Arrays;

public class CourseMain {

	public static void registerCourse(Course<?> course) {
		System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
	}

	public static void registerCourseStudent(Course<? extends Student> course) {
		System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
	}

	public static void registerCourseWorker(Course<? super Worker> course) {
		System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
	}


	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 GraduateStudent("대학원생"));

		Course<Worker> workerCourse = new Course<Worker>("직장인과정", 5);
		workerCourse.add(new Worker("직장인"));

		Course<Student> studentCourse = new Course<Student>("학생과정", 5);
		studentCourse.add(new Student("학생"));
		studentCourse.add(new GraduateStudent("대학원생"));

		Course<GraduateStudent> graduateStudentCourse = new Course<GraduateStudent>("대학원과정", 5);
		graduateStudentCourse.add(new GraduateStudent("대학원생"));

		registerCourse(personCourse);
		registerCourse(workerCourse);
		registerCourse(studentCourse);
		registerCourse(graduateStudentCourse);
		System.out.println();

		registerCourseStudent(studentCourse);
		registerCourseStudent(graduateStudentCourse);
//		registerCourseStudent(personCourse);	// Error
//		registerCourseStudent(workerCourse);	// Error
		System.out.println();

		registerCourseWorker(personCourse);
		registerCourseWorker(workerCourse);
//		registerCourseWorker(studentCourse);			// Error
//		registerCourseWorker(graduateStudentCourse);	// Error

	}
}