상세 컨텐츠

본문 제목

JAVA 12. 제네릭(Generic)

Backend/JAVA-자바

by 사랑짱 2021. 6. 27. 20:36

본문

 

◆ 제네릭(Generic) 타입이란?

- 타입을 파라미터로 가지는 클래스와 인터페이스, 메소드

- 선언 시 클래스 또는 인터페이스 이름 뒤에 '<>부호'를 붙이며,

  '<>' 사이에는 타입 파라미터가 위치.

- 개발코드에서 구체적인 타입을 지정하여 제네릭타입을 사용 ---> 타입의 일반화

 

※ 타입 파라미터

- 대문자 알파벳 한 문자로 표현

 

 

◆ 왜 제네릭을 사용해야할까?

- 컴파일 시 강한 타입 체크가 가능 ---> 잘못된 타입이 사용될 수 있는 문제를 제거

   (컴파일 시 제네릭 타입이 구체적인 타입으로 일괄 변환된다!!)

- 타입변환 제거 가능 ---> 프로그램 성능 효율적

 

출처 : 이것이 자바다

 

 

※ 제네릭 타입 사용 여부에 따른 비교

 

1) 클래스 생성 시 제네릭타입으로 선언하는 과정 비교

- 클래스 선언할 때 타입 파라미터를 사용한다.

 

 

2) 객체 생성 시, 제네릭타입 객체 생성/사용하는 과정 비교

- 컴파일 시 타입 파라미터가 구체적인 클래스로 변경된다.

 

 

 

◆ 멀티 타입 파라미터

- 제네릭 타입은 두 개 이상의 타입 파라미터 사용 가능 

 

출처 : 이것이 자바다

 

 

◆ 제네릭 메소드

- 매개변수 타입과 리턴타입으로 타입 파라미터를 갖는 메소드

 

※ 제네릭 메소드 선언 방법

출처 : 이것이 자바다

- 리턴타입 앞에 '<>'기호를 추가하여 메소드에 사용될 타입파라미터를 기재

- '<>'기호 안에 있는 타입 파라미터는 리턴 타입매개 변수에 사용 가능

  메소드 사용 시 구체적 타입으로 컴파일러가 바꿔줌!

 

※ 제네릭 메소드 호출 방법

- 리턴타입 변수 = <구체적타입> 메소드명(매개값);  --> 명시적으로 구체적 타입 지정

- 리턴타입 변수 = 메소드명(매개값);  --> 매개값을 보고 구체적 타입을 추정

  (단, 멀티타입 파라미터 사용 시 결과값에 오류가 발생할 수도 있다!)

 

 

<참고> 제네릭 타입의 배열은 어떻게 생성해야할까?

- 타입파라미터 즉, 제네릭타입의 배열은 직접 new 연산자로 생성이 불가능하다!
  따라서, 아래와 같은 순서로 생성해야 한다.

(1) Object[] 타입의 배열을 먼저 생성한다.
(2) (T[]) 강제 형변환하여 초기화 수행해야 한다.

(+) . 매개변수를 통해 인자값으로 배열의 길이를 받도록 하자!!

 

 

◆ 제네릭 타입의 상속과 구현

- 제네릭타입을 부모클래스로 사용하는 경우, 타입파라미터는 자식클래스에도 기술!!

  자식만의 타입 파라미터도 추가로 가질 수 있다!

 

 

◆ 제한된 타입 파라미터

- 타입 파라미터에 지정되는 구체적인 타입을 제한해야하는 경우 사용

- 타입 파라미터를 대체할 구체적일 타입 지정 가능!

 

 

※ HOW? 상속 및 구현 관계를 이용한 타입 제한

 

- <T extends 상위타입>

   : 지정가능한 구체타입에는 해당 상위타입이거나 상위타입을 상속받은 하위타입으로 제한

    (이 때, 상위타입의 멤버(필드, 메소드)들만 사용가능하다.)

 

- <T super 하위타입>

   : 지정가능한 구체타입에는 해당 하위타입이거나 하위타입이 상속받고 있는 상위타입으로 제한

 

 

◆ 와일드카드 타입

- 제네릭 객체를 인자값으로 받는 매개변수, 또는 지역변수(Lvalue)에

  제네릭타입을 사용할 때 와일드카드 타입 사용하여 여러 개의 구체타입 수용 가능!

 (단, 지역변수(Lvalue) 와일드카드 타입으로 선언 시, 메소드 호출에서 오류 발생!!)

 

1. 제네릭타입<?> : Unbounded Wildcards(제한없음)

- 타입 파라미터를 대치하는 구체적인 타입으로

  모든 클래스나 인터페이스 타입 수용가능

 

2. 제네릭타입<? extends 상위타입> : Upper Bounded Wildcards(상위 클래스 제한)

- 타입 파라미터를 대치하는 구체적인 타입으로

  해당 상위타입이나 상위타입을 상속받은 하위타입만 수용가능

 

3. 제네릭타입<? super 하위타입> : Lower Bounded Wildcards(하위 클래스 제한)

- 타입 파라미터를 대치하는 구체적인 타입으로

  해당 하위타입이거나 하위타입이 상속받고 있는 상위타입만 수용가능

 

 

아래 예시를 통해 와일드카드의 사용에 대해 직접 확인해보자!!

클래스 간 관계

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public class WildCardExample {
 
    //모든 사람을 대상으로 하는 교육과정 내역 출력
    public static void printCourse(Course<?> course) {
        log.info(
                course.getName() + "수강생"+
                Arrays.toString(course.getStudents())
        ); //info
    
    } //printCourse
 
    
    //학생을 대상으로 하는 교육과정의 내역 출력
    public static void printCourseStudent(
            Course<extends Student> course) {
        log.info(
                course.getName() + "수강생"+
                Arrays.toString(course.getStudents())
        ); //info
        
    } ///printCourseStudent
    
    
    //근로자를 대상으로 하는 교육과정의 내역 출력
    public static void printCourseWorker(
            Course<super Worker> course) {
            log.info(
                    course.getName() + "수강생"+
                    Arrays.toString(course.getStudents())
            ); //info
        
    } ///printCourseStudent
    
    public static void main(String[] args) {
        
        
        //1. 일반인을 대상으로 하는 교육과정을 생성, 이 때 "구체타입" 지정
        Course<Person> personCourse = new Course<>("일반인과정"5);    //타입추론
        
            personCourse.add(new Person("일반인"));
            personCourse.add(new Worker("직장인"));
            personCourse.add(new Student("학생"));
            personCourse.add(new HighStudent("고등학생"));
            
            
        //2. 직장인을 대상으로 하는 교육과정을 생성, 이 때 "구체타입" 지정
        Course<Worker> workerCourse = new Course<>("직장인과정"5);    //타입추론
 
//             workerCourse.add(new Person("일반인"));                    //worker 구체타입이기 때문에 XX
//             workerCourse.add(new Student("학생"));                    //worker 구체타입이기 때문에 XX
 
             workerCourse.add(new Worker("직장인"));
 
             Course<extends Person> course2 = personCourse;        //Course<Person>타입이 대입되어 Course<?>타입이 됨!
             Course<extends Person> course3 = workerCourse;        //Course<Person>타입이 대입되어 Course<?>타입이 됨!
                                                                     //다형성과 다르기 때문에 구분하기!!
        
             
        //3. 학생을 대상으로 하는 교육과정을 생성, 이 때 "구체타입" 지정
        Course<Student> studentCourse = new Course<>("학생과정"5);    //타입추론
 
            studentCourse.add(new Student("학생"));
            studentCourse.add(new HighStudent("고등학생"));            //다형성 1- 부모타입은 자식타입을 품을 수 있다!
        
            
        //4. 고등학생을 대상으로 하는 교육과정을 생성, 이 때 "구체타입" 지정
        Course<HighStudent> highStudentCourse = new Course<>("고등학생과정"5);    //타입추론
 
            highStudentCourse.add(new HighStudent("고등학생"));
        
        
        printCourse(personCourse);
        printCourse(workerCourse);
        printCourse(studentCourse);
        printCourse(highStudentCourse);
        
        log.info("******************************");
        
//        printCourseStudent(personCourse);            //수용XX
//        printCourseStudent(workerCourse);            //수용XX
        printCourseStudent(studentCourse);
        printCourseStudent(highStudentCourse);
        
        log.info("******************************");
        
        printCourseWorker(personCourse);
        printCourseWorker(workerCourse);
//        printCourseWorker(studentCourse);            //수용XX
//        printCourseWorker(highStudentCourse);        //수용XX    
        
    } //main
    
//end class
cs

관련글 더보기