[4기] 백엔드 개발자 부트캠프 "오르미" ~ing/[4기] 백엔드 개발자 부트캠프 오르미 수업 복습

[4기] 44일차 Java ( 제네릭2 )

sohee99 2024. 2. 14. 17:54

제네릭 메소드

 

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

 

public <타입파라미터, ..> 리턴타입 메소드명(매개변수, ...) { }

 

 

위와같이 리턴타입과 매개 타입으로 타입 파라미터 <T> 사용한다.

 

 

Box<Integer> box = boxing(100);

 

위와 같은 방식으로 호출이 가능하다. 매개값을 보고 구체적 타입을 추정 가능

 

public class Util {
    public static <T> Box<T> boxing(T t) {
        Box<T> box = new Box<T>();
        box.set(t);
        return box;
    }
}

 

Util 클래스에서 boxing() 정의 후 

 

public class GenericMethodExample {
    public static void main(String[] args) {
        Box<Integer> box1 = Util.boxing(100);
        int intValue = box1.get();

        Box<String> box2 = Util.boxing("홍길동");
        String strValue = box2.get();
    }
}

 

호출까지! 

- Integer 와 String 형식으로 저장하는 코드를 작성하는 것까지! 

 

 

제한된 타입 파라미터(<T extends 최상위타입>)

 

- 타입 파라미터에 구체적인 타입을 제한하는 기능 

 

음.. 이렇게 들으면 이게 먼교? 싶겠지만 

 

간단히 말하면 개발자가 원하는 타입만 올 수 있게 제한하는것! 이지 않을까? ㅎㅎ

 

숫자 연산하는 제네릭 메소드는 곧 넘버타입 혹은 Byte, Short, Integer, Long, Double 타입만을 가져야하는데 

 

이것이 제한된 타입 파라미터라고 한다! 

 

public <T extends 상위타입> 리턴타입 메소드(매개변수, ...) {
}

 

 

제한된 타입 파라미터는 이렇게 선언이 가능한데,

여기서 상위타입이란 클래스만이 아니라 인터페이스도 가능하다는거!

 

public static <T extends Number> int compare(T t1, T t2) {
    double v1 = t1.doubleValue();
    double v2 = t2.doubleValue();
    return Double.compare(v1, v2);
}

 

doubleValue() 는 넘버 클래스에 정의 되어있는 메소드이며

 

제공된 넘버 객체들의 숫자를 double타입으로 변환 한다. 

 

여기서! 

 

<T extends Number>은

매개변수 T가 number 클래스나 하위클래스로 제한된다는 뜻! 

그럼 제한 했으니 메서드에 전달되는 것은 넘버클래스나 하위클래스의 인스턴스만 가능하다는것!


또 한가지, Double.compare는

두 더블값을 비교하여 작으면 음수, 같으면 0 크면 1을 반환하는 메서드이다!

 

 

double.compare 메소드는 첫번째 매개값인 v1이 v2보다 작으면 -1 같으면 0 크면 1을 리턴 한다.

 

 

실행하게 되면?

 

 

public static void main(String[] args) {
    // String value = Util.compare("a", "b");   // String은 Number 타입이 아니므로 컴파일 오류 발생

    int result1 = Util.compare(1, 2);            // int -> Integer (자동 Boxing)
    System.out.println(result1);

    int result2 = Util.compare(4.5, 3);            // double -> Double (자동 Boxing)
    System.out.println(result2);
}

 

주석처리된 String은 당연히 넘버타입이 아니므로 오류 발생할 것이다!

 

출력값은 -1 1 이 나올것이다!!!

 

 

ㅎㅎㅎㅎㅎㅎㅎㅎ 출력값 잘나왔고!!

 

 

와일드카드 타입<?>, <? extends …>, <? super ..>

 

코드에서 ? 를 와일드 카드 (wildcard) 라고 불린다.

 

구체적인 타입 대신 와일드 카드를 사용 시 3가지 형태로 사용이 가능하다.

 

 

1. 제네릭 타입 <?> : 제한없엉 모든 클래스, 인터페이스 타입 가능! 

 

 

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

-  타입 파라미터를 대치하는 구체적인 타입으로 상위 타입이나 하위 타입만 올 수 있습니다.

 

 

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

- 타입 파라미터를 대치하는 구체적인 타입으로 하위 타입이나 상위 타입이 올 수 있습니다.

 

예시로 살펴보면!

 

출처 - 이스트소프트 조성연

 

Course<?>은 수강생의 경우 모든 타입이 가능하다는거! 

Course<? extends Student> 은 Student와 하위클래스인 HighStudent 만 가능! extend는 상위클래스를 제한한다했으니!

Course<? super Worker>의 경우는 Worker와 Person만 가능하겠졍? 하위 클래스를 제한한다했으므로~!

 

 

위의 그림대로 코드를 작성하면?

 

- 수강생 타입 4가지 클래스

 

<Course>

 

public class Course<T> {
    private String name;
    private T[] students;

    public Course(String name, int capacity) {
        this.name = name;
        this.students = (T[]) new Object[capacity];
    }

    public String getName() {
        return name;
    }

    public T[] getStudents() {
        return students;
    }

    public void add(T t) {
        for (int i = 0; i < students.length; i++) {
            if (students[i] == null) {
                students[i] = t;
                break;
            }
        }
    }
}

 

<person>

 

public class Person {
    private String name;
    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

 

<worker>

 

public class Worker extends Person {
    public Worker(String name) {
        super(name);
    }
}

 

<Student>

 

public class Student extends Person {
    public Student(String name) {
        super(name);
    }
}

 

<HighStudent>

 

public class HighStudent extends Student {
    public HighStudent(String name) {
        super(name);
    }
}

 

 

 

<WildCardExample>

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class WildCardExample {
    static void registerCourse(Course<?> course) {
        System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
    }

    static void registerStudentCourse(Course<? extends Student> course) {
        System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
    }

    static void registerWorkerCourse(Course<? super Worker> course) {
        System.out.println(course.getName() + " 수강생: " + Arrays.toString(course.getStudents()));
    }

    public static void main(String[] args) {
        List<Worker> workers = new ArrayList<>();
        List<Person> personList = new ArrayList<>();
        personList.addAll(workers);
//        workers.addAll(personList);

        Course<Person> personCourse = new Course<>("일반인과정", 4);
        personCourse.add(new Person("일반인"));
        personCourse.add(new Worker("직장인"));
        personCourse.add(new Student("학생"));
        personCourse.add(new HighStudent("고등학생"));

        Course<Worker> workerCourse = new Course<>("직장인과정", 4);
        workerCourse.add(new Worker("직장인"));

        Course<Student> studentCourse = new Course<>("학생과정", 4);
        studentCourse.add(new Student("학생"));
        studentCourse.add(new HighStudent("고등학생"));

        Course<HighStudent> highStudentCourse = new Course<>("고등학생과정", 4);
        highStudentCourse.add(new HighStudent("고등학생"));

        registerCourse(personCourse);
        registerCourse(workerCourse);
        registerCourse(studentCourse);
        registerCourse(highStudentCourse);
        System.out.println("-------------------------");

//        registerStudentCourse(personCourse);(X)
//        registerStudentCourse(workerCourse);(X)
        registerStudentCourse(studentCourse);
        registerStudentCourse(highStudentCourse);
        System.out.println("-------------------------");

        registerWorkerCourse(personCourse);
        registerWorkerCourse(workerCourse);
//        registerWorkerCourse(studentCourse);(X)
//        registerWorkerCourse(highStudentCourse);(X)
    }
}

 

이것의 출력값은?

 

 

registerCourse() : 모든 수강생들이 들을 수 있는 과정을 등록하고

registerCourseStudent() : 학생만 들을 수 있는 과정을 등록합니다

registerCourseWorker() : 직장인만 들을 수 있는 과정을 등록합니다.

 

 

 

ㅎㅎㅎㅎㅎ오오!!!! 신기해엽ㅋㅋㅋㅋㅋㅋㅋㅋㅎㅎㅎ

 

 

이게진짜 강의를 들으면서 깨달은건데 전 강의도 잘 가르쳐주시긴하지만 

 

독학 체질인가봐요... 이해가 혼자 읽을 때 집중을 좀 더 잘하게 되네요? 

 

 

음 개념을 강사님께 이미 한번 들어서 그런가 ??ㅎㅎㅎㅎ 

 

 

역시 복습이 젤 좋은거같다는 생각이 드네요 ㅎㅎㅎ!!! 

 

 

 

이 개념의 이해는 된거 같지만 막상 문제가 주어지고 

작성을 혼자 하게된다면 ..... ㅎ.... 아마 힘들 거 같다는 생각이... ㅎㅎ

 

 

 

그래도 실습을 열심히 많이 해봐야 느니깐.... !!

 

제네릭 타입의 상속과 구현

 

제네릭타입도 다른 타입과 같이 부모클래스가 될 수 있다는거! 그럼 상속이 가능하다는거 ㅎㅎㅎ!!

 

public class ChildProduct<T, M, C> extends Product<T, M> {
}

 

이렇게 부모클래스가 될수도 있으며 자식 제네릭타입은 타입 파라미터를 추가로 가질 수도 있다! 

 

상속(inherit)

 

public class Product<T, M> {
    private T kind;
    private M model;

    public T getKind() {
        return kind;
    }

    public M getModel() {
        return model;
    }

    public void setKind(T kind) {
        this.kind = kind;
    }

    public void setModel(M model) {
        this.model = model;
    }
}

 

부모 제네릭 클래스 Product 를 

 

public class ChildProduct<T, M, C> extends Product<T, M> {
    private C company;

    public C getCompany() {
        return this.company;
    }

    public void setCompany(C company) {
        this.company = company;
    }
}

 

ChildProduct가 상속받은 코드 작성해보기! 

 

- 이 코드에서도 부모제네릭클래스에서 상속받고 자식 제네릭 클래스에서 C를 추가한 모습!

 

구현(implements)

 

제네릭 클래스가 있다면 제네릭 인터페이스도 존재하겠죵?

 

public interface Storage<T> {
    void add(T item, int index);

    T get(int index);
}

 

Storage<T> 타입을 구현한 StorageImpl 클래스도 제네릭 타입이여야 한다!

 

코드 작성하면?

 

public class StorageImpl<T> implements Storage<T> {
    private T[] items;

    public StorageImpl(int capacity) {
        items = (T[]) new Object[capacity];
    }

    @Override
    public void add(T item, int index) {
        items[index] = item;
    }

    @Override
    public T get(int index) {
        return items[index];
    }
}

 

 

이렇게 오늘 제네릭에 대해 공부했는데엽!!!

 

나름 이해는 잘 됐지만 코드 작성연습을 많이 해봐야 늘거 같다는 생각이 드네요 ㅠ

 

오늘은 데일리 퀴즈 풀고! 

 

sql 자격증 공부하고 자야겠어욤!!! 

 

한번 더 복습하고 싶은데,,, ㅠ 연휴다음날이라 너무 피곤하달까요 ㅠ ㅋㅋㅋ큐ㅠ 

 

자격증은 1달도 안남았으니 자격증 부터 공부할 예정입니다! 

 

오늘도 파이팅했구 !

 

내일도 파이팅@!!!!!!!!!!!!!!