제네릭(Generic)

용씨·2023년 2월 4일
0

자바 개념 시리즈

목록 보기
9/9

개념

제네릭(Generic)이란 결정되지 않은 타입을 파라미터로 처리하고 실제 사용할 때 파라미터를 구체적인 타입으로 대체시키는 기능이다.

public class Box {
	public ? content
}

다양한 내용물을 저장할 Box 클래스를 선언하려고 한다. conent의 타입을 무엇으로 해야 할까?

  • Object 타입?

모든 클래스의 루트 클래스인 Object를 넣으면 되지 않을까?

그럴듯하지만 객체의 내용물을 꺼낼 때 문제가 생긴다. content의 타입을 모르기 때문에 매번 instanceof 연산자로 타입을 조사해야 한다. 이는 좋은 방법이 아니다.

Box를 생성하기 전에 우리는 어떤 내용물을 넣을지 이미 알고 있다. 따라서 Box를 생성할 때 저장할 내용물의 타입을 미리 알려주면 Box는 content에 무엇이 대입되고, 읽을 때 어떤 타입으로 제공할지를 알게 된다. 이것이 제네릭이다.

public class Box<T> {
	public T content
}

<T>는 T가 타입 파라미터임을 뜻하는 기호이다. <Integer>, <String> 등 타입을 넣을 수 있다.
T에 대체되는 타입은 클래스 및 인터페이스이어야 한다. int, char 같은 기본 타입은 들어갈 수 T가 될 수 없다.

T는 단지 이름이다. 어떤 알파벳을 써도 상관없다.

사용 예시

public class Main {

    public static void main(String[] args)  {
        Box<String> box1 = new Box<>();
        box1.content = "안녕하세요";
        String str = box1.content;
        System.out.println(str);

        Box<Integer> box2 = new Box<>();
        box2.content = 100;
        int value = box2.content;
        System.out.println(value);
    }

}

타입 파라미터의 제한

타입 파라미터를 제한할 수 있다. 제한된 타입 파라미터를 bounded type parameter 라고 한다.

사용 예시

이제 Box의 T 타입은 Number와 Number의 자식, Number의 구현 관계에 있는 타입만 가능하다. 상위 타입은 클래스와 인터페이스가 들어올 수 있다.

public class Box<T extends Number>{
    public T content;
}

T타입을 String으로 선언하면 오류가 발생한다.

와일드카드 타입 파라미터

제네릭 타입을 매개값이나 리턴 타입으로 사용할 때 타입 파라미터로 ?(와일드카드)를 사용할 수 있다.

extends와 super

<? extends 타입><? super 타입>의 차이는 다음과 같다.

https://jojozhuang.github.io/programming/java-core-generics/

사용 예시

Applicant 클래스 - 타입 파라미터 사용하는 클래스

public class Applicant<T>{

    public T kind;

    public Applicant(T kind) {
        this.kind = kind;
    }
}

Person 클래스와 자식 클래스들

public class Person {

}

class Worker extends Person {

}

class Student extends Person {

}

class HighStudent extends Student {

}

class MiddleStudent extends Student {

}

와일드카드 타입 파라미터 - 매개값

  1. Applicant<?> applicant: 어떤 타입이든 가능
  2. Applicant<? extends Student> applicant: Student와 Student의 자손 클래스만 가능
  3. Applicant<? super Worker> applicant: Worker와 Worker의 조상 클래스만 가능
public class Course {

    public static void registerCourse(Applicant<?> applicant) {
        System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) Course를 등록함");
    }

    public static void regeisterCourseOnlyStudent(Applicant<? extends Student> applicant) {
        System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) CourseOnlyStudent를 등록함");
    }

    public static void registerCourseOnlyWorker(Applicant<? super Worker> applicant) {
        System.out.println(applicant.kind.getClass().getSimpleName() + "이(가) CourseOnlyWorker를 등록함");
    }
}

코드에 적용

매개 타입이 맞지 않아 오류가 나는 모습이다.
주석처리 해주자.

public class Main {

    public static void main(String[] args)  {

        // 모든 사람이 신청 가능
        System.out.println("모든 사람이 신청 가능");
        Course.registerCourse(new Applicant<Person>(new Person()));
        Course.registerCourse(new Applicant<Worker>(new Worker()));
        Course.registerCourse(new Applicant<Student>(new Student()));
        Course.registerCourse(new Applicant<HighStudent>(new HighStudent()));
        Course.registerCourse(new Applicant<MiddleStudent>(new MiddleStudent()));
        System.out.println();

        // 학생만 신청 가능
        System.out.println("학생만 신청 가능");
//        Course.regeisterCourseOnlyStudent(new Applicant<Person>(new Person()));
//        Course.regeisterCourseOnlyStudent(new Applicant<Worker>(new Worker()));
        Course.regeisterCourseOnlyStudent(new Applicant<Student>(new Student()));
        Course.regeisterCourseOnlyStudent(new Applicant<HighStudent>(new HighStudent()));
        Course.regeisterCourseOnlyStudent(new Applicant<MiddleStudent>(new MiddleStudent()));
        System.out.println();

        //직장인 및 일반인만 신청 가능
        System.out.println("직장인 및 일반인만 신청 가능");
        Course.registerCourseOnlyWorker(new Applicant<Person>(new Person()));
        Course.registerCourseOnlyWorker(new Applicant<Worker>(new Worker()));
//        Course.registerCourseOnlyWorker(new Applicant<Student>(new Student()));
//        Course.registerCourseOnlyWorker(new Applicant<HighStudent>(new HighStudent()));
//        Course.registerCourseOnlyWorker(new Applicant<MiddleStudent>(new MiddleStudent()));
    }

}
// 실행결과
모든 사람이 신청 가능
Person이(가) Course를 등록함
Worker이(가) Course를 등록함
Student이(가) Course를 등록함
HighStudent이(가) Course를 등록함
MiddleStudent이(가) Course를 등록함

학생만 신청 가능
Student이(가) CourseOnlyStudent를 등록함
HighStudent이(가) CourseOnlyStudent를 등록함
MiddleStudent이(가) CourseOnlyStudent를 등록함

직장인 및 일반인만 신청 가능
Person이(가) CourseOnlyWorker를 등록함
Worker이(가) CourseOnlyWorker를 등록함
profile
아침형 인간이 목표

0개의 댓글