군만두의 IT 공부 일지

[스터디4] 06. 제네릭 본문

프로그래밍/Java

[스터디4] 06. 제네릭

mandus 2025. 3. 2. 11:48

목차

    13장. 제네릭

    13.1 제네릭이란?

    Box 클래스에 넣을 내용물을 content 필드라고 선언하려고 할 때, 타입을 무엇으로 해야 할까?

    public class Box {
        public Object content;
    }
    
    Box box = new Box();
    box.content = 모든 객체;

    Box는 다양한 내용물을 저장해야 하므로 특정 클래스 타입으로 선언할 수 없기 때문에, Object 타입으로 선언한다. 모든 객체는 부모 타입인 Object로 자동 타입 변환이 되므로, content 필드에는 어떤 객체든 대입이 가능하다.

    • Object 타입: 모든 클래스의 최상위 부모 클래스
    • 문제: Box 안의 내용물을 얻을 때, 어떤 객체가 대입되어 있는지 확실하지 않다. instanceof 연산자로 모든 종류의 클래스를 조사하여 강제 타입 변환을 할 수는 없다.

    Box를 생성할 때 저장할 내용물의 타입을 미리 알려주면 Box는 content에 무엇이 대입되고, 읽을 때 어떤 타입으로 제공할지를 알게 된다.

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

    Box 클래스에서 결정되지 않은 content 타입을 T라는 타입 파라미터로 정의한다. Box 클래스는 T가 무엇인지 모르지만, Box 객체가 생성될 시점에 다른 타입으로 대체된다는 것을 알고 있다.

    public class Box <T> {	// <T>: T가 타입 파라미터임을 뜻하는 기호
        public T content;
    }
    
    Box<String> box = new Box<String>();
    box.content = "안녕하세요.";
    String content = box.content;	// 강제 타입 변환 필요 없음
    
    Box<Integer> box = new Box<Integer>();
    box.content = 100;
    int content = box.content;	// 강제 타입 변환 필요 없음

    Box의 내용물로 String이나 100을 저장하고 싶다면, 타입 파라미터 T 대신 String이나 Integer로 대체한다.

    • <T>에서 T는 이름일 뿐이므로 A부터 Z까지 어떤 알파벳을 사용해도 된다. 일반적으로 대문자 알파벳 한 글자로 표현된다.
    • 타입 파라미터를 대체하는 타입은 클래스인터페이스다.
    • 변수를 선언할 때와 동일한 타입으로 호출하고 싶다면, 생성자 호출 시 생성자에는 타입을 명시하지 않고 <>만 붙인다.
    Box<String> box = new<>(String); -> Box<String> box = new<>();

    13.2 제네릭 타입

    • 제네릭 타입: 결정되지 않은 타입을 파라미터로 가지는 클래스와 인터페이스
    • 제네릭 타입은 선언부에 '<>' 부호가 붙고 그 사이에 타입 파라미터들이 위치한다.
    • 외부에서 제네릭 타입을 사용하려면 타입 파라미터에 구체적인 타입을 지정해야 한다. (Object 타입이 디폴트)
    • 타입 파라미터는 기본적으로 Object 타입으로 간주되므로 Object가 가지고 있는 메소드를 호출할 수 있다.
    public class 클래스명<A, B, ...> { ... }
    public interface 인터페이스명<A, B, ...> { ... }
    package ch13.sec02.exam01;
    
    // 제네릭 타입
    public class Product<K, M> {	// 타입 파라미터로 K와 M 정의
        // 필드
        private K kind;				// 타입 파라미터를 필드 타입으로 사용
        private M model;
    
        // 메서드
        public K getKind() { return this.kind; }	// 타입 파라미터를 리턴 타입과 매개 변수 타입으로 사용
        public M getModel() { return this.model; }
        public void setKind(K kind) { this.kind = kind; }
        public void setModel(M model) { this.model = model; }
    }

    13.3 제네릭 메소드

    • 제네릭 메소드: 타입 파라미터를 가지고 있는 메소드
    • 제네릭 메소드는 리턴 타입 앞에 <> 기호를 추가하고 타입 파라미터를 정의한 뒤, 리턴 타입과 매개변수 타입에서 사용한다.\
    • 타입 파라미터 T는 매개값이 어떤 타입이냐에 따라 컴파일 과정에서 구체적인 타입으로 대체된다.

    boxing() 메소드는 타입 파라미터로 <T>를 정의하고 매개변수 타입과 리턴 타입에서 T를 사용한다. 정확한 리턴 타입은 T를 내용물로 갖는 Box 객체이다.

    public <T> Box<T> boxing(T t) { ... }
    1) Box<Integer> box1 = boxing(100);		// Box<Intrger> 리턴
    2) Box<String> box2 = boxing<"안녕하세요");	// Box<String> 리턴

    13.4 제한된 타입 파라미터

    경우에 따라 타입 파라미터를 대체하는 구체적인 타입을 제한할 필요가 있다.

    • 제한된 타입 파라미터(bounded type parameter): 모든 타입으로 대체할 수 없고, 특정 타입과 자식 또는 구현 관계에 있는 타입만 대체할 수 있는 타입 파라미터
    • 상위 타입은 클래스, 인터페이스가 가능하다. 이때, 인터페이스라고 implements를 사용하지 않는다.
    • 타입 파라미터가 제한되면서 Object의 메소드뿐만 아니라 제한된 타입이 가지고 있는 메소드도 사용할 수 있다.
    public <T extends 상위타입> 리턴타입 메소드(매개변수, ...) { ... }
    // 제한된 타입 파라미터를 갖는 제네릭 메소드
    public <T extends Number> boolean compare(T t1, T t2) {
        double v1 = t1.doubleValue();  // Number의 doubleValue() 메서드 사용
        double v2 = t2.doubleValue();  // Number의 doubleValue() 메서드 사용
        return (v1 == v2);
    }

    13.5 와일드카드 타입 파라미터

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

    • ?: 범위에 있는 모든 타입으로 대체할 수 있다는 표시

    // 타입 파라미터의 대체 타입으로 Student와 자식 클래스인 HighStudent와 MiddleStudent만 가능하도록 매개변수 선언
    리턴타입 메소드명(제네릭타입<? extends Student> 변수) { ... }
    
    // 타입 파라미터의 대체 타입으로 Worker와 자식 클래스인 Person만 가능하도록 매개변수 선언
    리턴타입 메소드명(제네릭타입<? super Worker> 변수) { ... }
    
    // 어떤 타입이든 가능하도록 매개변수 선언
    리턴타입 메소드명(제네릭타입<?>변수) { ... }

     

    이 글은 『이것이 자바다』 책을 학습한 내용을 정리한 것입니다.
    Comments