[Java] 제네릭(Generics)

✨New Wisdom✨·2020년 12월 10일
0

📕 Java 📕

목록 보기
6/24
post-thumbnail

이 노트는 "윤성우의 열혈 java 프로그래밍" 책을 공부하면서
내가 이해한대로 다시 정리하면서 작성되었다.

제네릭의 이해

🤔 제네릭?
제네릭이 갖는 의미는 일반화이다. 여기서 일반화의 대상은 자료형이다.
제네릭이 등장하면서 자료형에 의존적이지 않은 클래스를 정의할 수 있게 되었다.

제네릭을 쓰는 이유

class Apple {
    public String toString() {
        return "I am an apple.";
    }    
}

class Orange {
    public String toString() {
        return "I am an orange.";
    }
}

class Box {
    private Object ob;

    public void set(Object o) {
        ob = o;
    }
    public Object get() {
        return ob;
    }
}


class FruitAndBox2 {
    public static void main(String[] args) {
        Box aBox = new Box();
        Box oBox = new Box();

        // 상자에 과일을 담는다.
        aBox.set(new Apple());
        oBox.set(new Orange());

        // 상자에서 과일을 꺼낸다.
        Apple ap = (Apple)aBox.get();
        Orange og = (Orange)oBox.get();

        System.out.println(ap);
        System.out.println(og);
    }
}

위의 코드에서 Box 내에서 인스턴스를 저장하는 참조변수가 Object이기 때문에 내용물을 꺼낼 때는 형 변환이 필요하다.
또는 담은 자료형과 꺼내는 자료형이 다르다면 컴파일 에러가 난다.
제네릭을 사용하지 않는다면,

  • 필요시 형 변환을 해야 한다.
  • 자료형과 관련된 프로그래머의 실수가 컴파일 과정에서 드러나지 않는다.

제네릭 기반 클래스 정의하기

위의 Box 클래스를 변경해본다.

class Box<T> {
    private T ob;

    public void set(T o) {
        ob = o;
    }
    public T get() {
        return ob;
    }
}

T 는 인스턴스를 생성할 때 결정하면 된다.
인스턴스 생성 시 T의 자료형을 결정하는 것이 '제네릭'이다.

제네릭 기반 클래스의 인스턴스 생성

Box<Apple> aBax = new Box<Apple>();
  • T를 Apple로 결정하여 인스턴스 생성.
  • 따라서 Apple 또는 Apple을 상속하는 하위 클래스의 인스턴스 저장 가능.

타입 매개변수

Box<T> 에서 T

타입 인자

Box<Apple>에서 Apple

매개변수화 타입 = 제네릭 타입

Box<Apple>

제네릭의 기본 문법

다중 매개변수 기반 클래스의 정의

칸이 둘로 나뉘어 진 상자를 표현한 제네릭 클래스 정의이다.

class DBox<L, R> {
    private L left;     // 왼쪽 수납 공간
    private R right;    // 오른쪽 수납 공간
    
    public void set(L o, R r) {
        left = o;
        right = r;
    } 
    
    @Override
    public String toString() {
        return left + " & " +right;
    }
}

class MultiTypeParam {
    public static void main(String[] args) {
        DBox<String, Integer> box = new DBox<String, Integer>();
        box.set("Apple", 25);
        System.out.println(box);
    }
}

타입 매개변수의 규칙

  • 한 문자로 이름을 짓는다.
  • 대문자로 이름을 짓는다.

기본 자료형에 대한 제한

매개변수화 타입을 구성할 때 기본 자료형의 이름은 타입 인자로 쓸 수 없다.
하지만 기본 자료형에 대한 래퍼 클래스가 존재하고, 필요 상황에서 박싱과 언박싱이 자동으로 이뤄지니,
다음과 같이 정의할 수 있다.

class Box<T> {
    private T ob;

    public void set(T o) {
        ob = o;
    }
    public T get() {
        return ob;
    }
}

class PrimitivesAndGeneric {
    public static void main(String[] args) {
        Box<Integer> iBox = new Box<Integer>();
    
        iBox.set(125);
        int num = iBox.get();

        System.out.println(num);
    }
}

타입 인자의 생략

다이아몬드 기호

컴파일러는 제네릭 관련 문장에서 자료형의 이름을 추론하는 능력을 가지고 있다.
따라서
Box<Apple> aBox = new Box<Apple>();Box<Apple> aBox = new Box<>(); 와 같이 쓸 수 있다.

타입 인자 제한하기

Box<T> 에는 무엇이든 담을 수 있었지만, 클래스는 그 특성과 용도가 있으니 자료형을 제한할 수 있어야 한다.
이때 extends 를 사용해 타입 인자를 제한한다.

class Box<T extends Number> {...}
  • 인스턴스 생성 시 타입 인자로 Number 또는 이를 상속하는 클래스만 올 수 있다.

제네릭 메소드의 정의

클래스 뿐만 아니라 일부 메소드에 대해서만 제네릭으로 정의하는 것도 가능하다.
static 선언의 유무에 상관없이 제네릭 메소드의 정의가 가능하다.

public static <T> Box<T> makeBox(T o) {...}
  • 메소드의 이름은 makeBox이고, 반환형은 Box<T>이다.
  • static과 Box<T> 사이에 위치한 <T>는 T가 타입 매개변수임을 알리는 표시다.
profile
🚛 블로그 이사합니다 https://newwisdom.tistory.com/

0개의 댓글