1. 5. 와일드카드 타입 ,
제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 구체적인 타입 대신에 와일드카드(?)를 사용할 수 있다.
- <?> : 제한없음
- <? extends 타입> : 지정된 타입 또는 하위 타입만 올 수 있다.
- <? super 타입> : 지정된 타입 또는 상위 타입만 올 수 있다.
2. 5-1. 제네릭에서 와일드카드의 사용
<java />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
<java />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)); } }
3. 5-2. 함수형인터페이스를 활용할 때 ?(와일드카드) 사용
<java />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 |