5. 와일드카드 타입 <?>, <? extends ...> <? super ...>
제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 구체적인 타입 대신에 와일드카드(?)를 사용할 수 있다.
- <?> : 제한없음
- <? extends 타입> : 지정된 타입 또는 하위 타입만 올 수 있다.
- <? super 타입> : 지정된 타입 또는 상위 타입만 올 수 있다.
5-1. 제네릭에서 와일드카드의 사용
public class Course<T> {
private String name;
private T[] students;
private int index;
private final int capacity;
public Course(String name, int capacity) {
this.name = name;
this.capacity = capacity;
this.students = (T[])(new Object[capacity]);
this.index = 0;
}
public String getName() { return name;}
public T[] getStudents() {return students;}
public void add(T t) {
Assert.isTrue(index < capacity, "Capacity를 초과했습니다.");
students[index] = t;
index++;
}
}
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() { return name; }
@Override
public String toString() {
return name;
}
}
public class Worker extends Person {
public Worker(String name) {
super(name);
}
}
public class Student extends Person {
public Student(String name) {
super(name);
}
}
public class HighStudent extends Student {
public HighStudent(String name) {
super(name);
}
}
Person
|
|-----------
| |
Worker. Student
|
HighStudent
class CourseTest {
private static void registerCourse(Course<?> course) {
return;
}
private static void registerCourseStudentByWildcards(
Course<? extends Student> course
) {
return;
}
@Test
void 와일드카드테스트() {
registerCourse(new Course<Person>("일반인 과정", 5));
registerCourse(new Course<Student>("학생 과정", 5));
registerCourse(new Course<Worker>("근로자 과정", 5));
registerCourse(new Course<HighStudent>("고등학생 과정", 5));
//registerCourseStudentByWildcards(new Course<Person>("일반인 과정", 5)); //캐스팅 에러 발생함
registerCourseStudentByWildcards(new Course<Student>("학생 과정", 5));
//registerCourseStudentByWildcards(new Course<Worker>("근로자 과정", 5)); //캐스팅 에러 발생함
registerCourseStudentByWildcards(new Course<HighStudent>("고등학생 과정", 5));
}
}
5-2. 함수형인터페이스를 활용할 때 ?(와일드카드) 사용
public class FunctionalProgram4Test {
private static <T> Consumer<T> printAny() {
return t -> System.out.println(t.toString());
}
private static Consumer<? super Number> printNumber() {
return t -> System.out.println(t.toString());
}
// 함수형 인자로 Comsumer<T> 가능
private static <T> void printAnyByFunction(Consumer<T> prt, T t) {
prt.accept(t);
}
//제너릭 <T extends String>으로 선언 후 함수형 인자로 <? super T> 가능
//왜냐? T exteds String 조건에 만족하는 인자는 모두 <? Super T> 조건에 부합하니까 가능함
private static <T extends String> void printStringByFunction(Consumer<? super T> prt, T t) {
prt.accept(t);
}
// <T extends String>를 <? extends T>로 변환은 불가능
// String에게 3세대의 자식 클래스 계층이 있다고 할 때,
// 3세대를 2세대로 변환은 가능하지만,
// 2세대를 3세대로 변환은 불가능
// (부모는 자식을 품을 수 있지만, 자식은 부모를 품지 못한다는 인생의 진리가 개발 언어에도 녹가 있는...)
/*
private static <T extends String> void printStringByFunction(Consumer<? extends T> prt, T t) {
prt.accept(t);
}
*/
@Test
void test() {
Consumer<String> prtAny = printAny();
prtAny.accept("Hello world!!");
var prtNumber = printNumber();
prtNumber.accept(1);
Stream<String> s = Arrays.asList("Test", "Abc", "Hello List").stream();
s.forEach(prtAny);
Stream<Long> sl = Arrays.asList(1L, 2L, 100L).stream();
sl.forEach(prtNumber);
printStringByFunction(printAny(), "이건 된다.");
//printStringByFunction(printNumber(), "이건 안된다.");
printAnyByFunction(printAny(), 1L);
printAnyByFunction(printNumber(), 1L);
}
@Test
void test2() {
// 하나 더 해보자.
Consumer<? super String> prtLambda = (t) -> System.out.println(t);
prtLambda.accept( "Test" );
printAnyByFunction(prtLambda, "Test");
}
}
안되는 케이스 화면 캡처
'프로그래밍 > Java-Spring' 카테고리의 다른 글
Java 함수형 프로그래밍 (0) | 2023.01.17 |
---|---|
Java 8 함수형 인터페이스 (Functional Interface) (0) | 2023.01.11 |
@RequiredArgsConstructor 를 이용한 의존성 주입 (0) | 2022.12.14 |
매개변수 유효성 검사 Objects.requireNonNull() 및 Test 코드 (0) | 2022.12.07 |
Multi SpringApplication 을 선택 처리하는 방법 (0) | 2021.02.26 |