Justin의 개발 로그
article thumbnail

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"); } }

 

안되는 케이스 화면 캡처

profile

Justin의 개발 로그

@라이프노트

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!