1. 제네릭 - Generic1

제네릭 적용

제네릭을 사용하면 코드 재사용성타입 안정성이라는 두 마리 토끼를 한 번에 잡을 수 있다.

package generic.ex1;

public class GenericBox<T> {

    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}
package generic.ex1;

public class BoxMain3 {

    public static void main(String[] args) {

        GenericBox<Integer> integerGenericBox = new GenericBox<>();
        integerGenericBox.set(10);
        Integer integer = integerGenericBox.get();
        System.out.println("integer = " + integer);

        GenericBox<String> stringGenericBox = new GenericBox<>();
        stringGenericBox.set("hello");
        String string = stringGenericBox.get();
        System.out.println("string = " + string);

    }
}

원하는 모든 타입 사용 가능

제네릭 클래스를 사용하면 다음과 같이 GenericBox 객체를 생성 시점(런타임)에 원하는 타입을 마음껏 지정할 수 있다.

참고로 제네릭을 도입한다고 해서 앞서 설명한 GenericBox<String> , GenericBox<Integer> 와 같은 코드가 실제 만들어지는 것은 아니다.

대신에 자바 컴파일러가 우리가 입력한 타입 정보를 기반으로 이런 코드가 있다고 가정하고 컴파일 과정에 타입 정보를 반영한다. 이 과정에서 타입이 맞지 않으면 컴파일 오류가 발생한다.

타입 추론

첫번째 줄의 코드를 보면 변수를 선언할 때와 객체를 생성할 때 <Integer> 가 두 번 나온다. 자바는 왼쪽에 있는 변수를 선언할 때의 <Integer> 를 보고 오른쪽에 있는 객체를 생성할 때 필요한 타입 정보를 얻을 수 있다.

따라서, 두번째 줄의 오른쪽 코드 new GenericBox<>() 와 같이 타입 정보를 생략할 수 있다. 이렇게 자바가 스스로 타입 정보를 추론해서 개발자가 타입 정보를 생략할 수 있는 것을 "타입 추론" 이라 한다.

참고로 타입 추론이 그냥 되는 것은 아니고, 자바 컴파일러가 타입을 추론할 수 있는 상황에만 가능하다. 쉽게 이야기해서 읽을 수 있는 타입 정보가 주변에 있어야 추론할 수 있다.

제네릭 용어와 관례

제네릭의 핵심은 사용할 타입을 미리 결정하지 않는다는 점이다. 클래스 내부에서 사용하는 타입의 클래스를 정의하는 시점에 결정하는 것이 아니라, 실제 사용하는 생성 시점에 타입을 결정하는 것이다.

용어 정리

  • 제네릭(Generic) 단어

    • 제네릭이라는 단어는 일반적인, 범용적인이라는 영어 단어 뜻이다.

    • 풀어보면 특정 타입에 속한 것이 아니라 일반적으로, 범용적으로 사용할 수 있다는 뜻이다.

  • 제네릭 타입 (Generic Type)

    • 클래스나 인터페이스를 정의할 때 타입 매개변수를 사용하는 것을 말한다.

    • 제네릭 클래스, 제네릭 인터페이스를 모두 합쳐서 제네릭 타입이라 한다.

      • 타입은 클래스, 인터페이스, 기본형( int 등)을 모두 합쳐서 부르는 말이다.

    • 예: class GenericBox<T> { private T t; }

    • 여기에서 GenericBox<T> 를 제네릭 타입이라 한다.

  • 타입 매개변수 (Type Parameter)

    • 제네릭 타입이나 메서드에서 사용되는 변수로, 실제 타입으로 대체된다.

    • 예: GenericBox<T>

    • 여기에서 T 를 타입 매개변수라 한다.

  • 타입 인자 (Type Argument)

    • 제네릭 타입을 사용할 때 제공되는 실제 타입이다.

    • 예: GenericBox<Integer>

    • 여기에서 Integer 를 타입 인자라 한다.

제네릭 명명 관례

타입 매개변수는 일반적인 변수명처럼 소문자로 사용해도 문제는 없다. 하지만 일반적으로 대문자를 사용하고 용도에 맞는 단어의 첫글자를 사용하는 관례를 따른다.

주로 사용하는 키워드는 다음과 같다.

  • E - Element

  • K - Key

  • N - Number

  • T - Type

  • V - Value

  • S,U,V etc. - 2nd, 3rd, 4th types

제네릭 기타

다음과 같이 한번에 여러 타입 매개변수를 선언할 수 있다.

타입 인자로 기본형은 사용할 수 없다.

  • JVM 은 컴파일 후 타입 소거(ereaser) 를 하게 된다. 이렇게 되면 제네릭 타입 인자는 상한 제한이 있지 않는 경우 Object 로 치환되게 된다.

  • 하지만 객체인 Object 와 기본형 타입은 사용하는 메모리 구조가 다르기 때문에, 이를 허용해 줄 경우 JVM 메모리 사용의 어려움을 겪을 수 있다.

    • 레퍼런스 타입 : 힙 영역

    • 기본형 타입 : 스택 영역

때문에, 제네릭의 타입 인자로 기본형( int, double ..)은 사용할 수 없다. 대신에 래퍼 클래스( Integer , Double)를 사용 하면 된다.

Last updated