Java Mid 12 - Generic 1

제네릭이란

정적언어(C, C++,Java)을 다뤄봤다면 제네릭(Generic)에 대해 잘 알지는 못하더라도 한 번쯤은 들어봤을 것이다. 특히 자료구조 같이 구조체를 직접 만들어 사용할 때 많이 쓰이기도 하고 매우 유용하기도 하다.

제네릭(Generic)은 직역하자면 ‘일반적인’이라는 뜻이다. 조금 더 직관적으로 말하자면 ‘데이터 형식에 의존하지 않고, 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법’이다.

만약에 우리가 어떤 자료구조를 만들어 배포하려고 한다. 그런데 String 타입도 지원하고싶고 Integer타입도 지원하고 싶고 많은 타입을 지원하고 싶다. 그러면 String에 대한 클래스, Integer에 대한 클래스 등 하나하나 타입에 따라 만들 것인가? 비효율적이다. 이러한 문제를 해결하기 위해 우리는 제네릭이라는 것을 사용한다.

이렇듯 제네릭(Generic)은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미한다. 한마디로 특정(Specific) 타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic) 타입이라는 것이다.

제네릭 적용

제네릭의 핵심 개념을 쉽게 설명하자면, 클래스나 메서드에서 사용할 타입을 미리 고정하지 않고, 실제 사용할 때 결정하는 것이라고 볼 수 있다.

비유하자면, 메서드에서 매개변수는 그 값을 정하지 않고 자리를 마련해 두는 것과 비슷하다. 메서드를 호출할 때 인자를 넣으면 그 값이 매개변수로 들어가는 것이다.

제네릭도 이와 비슷하게, 클래스나 메서드를 정의할 때는 타입을 고정하지 않고, 실제 사용할 때 타입을 넣어서 구체적으로 결정하는 방식이다.

public class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

여기서 T는 미리 정해지지 않은 타입이고, 이 클래스를 사용할 때 T의 구체적인 타입을 정한다.


Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");

Box<Integer> intBox = new Box<>();
intBox.setItem(123);

Box 클래스는 T라는 타입을 미리 고정하지 않고, 사용할 때 String, Integer 등 원하는 타입을 결정하는 구조입니다. 마치 메서드가 호출될 때 인자를 받는 것처럼, 제네릭 클래스도 사용할 때 타입을 지정한다.

package generic.ex1;

public class BoxMain3 {
    public static void main(String[] args) {
        GenericBox<Integer> integerBox = new GenericBox<Integer>(); //생성 시점의 T의 타입이 결정이 된다.
        integerBox.set( 10 );
        //integerBox.set() //Integer type만 허용
        Integer integer = integerBox.get(); //casting할 필요가 없어짐.
        System.out.println( "integer = " + integer );

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

        //원하는 모든 타입 사용가능
        GenericBox<Double> doubleGenericBox = new GenericBox<>();
        doubleGenericBox.set( 10.5 );
        Double v = doubleGenericBox.get();
        System.out.println( "v = " + v );
    }
    
    //타입 추론: 생성하는 제네릭 타입 생략 가능
}

제네릭 용어와 관례

제네릭의 핵심은 사용할 타입을 미리 결정하지 않는 점에 있다.

클래스 내부에서 사용하는 타입을 클래스를 정의하는 시점에 결정하는 것이 아니라, 실제 사용하는 생성 시점에 타입을 결정하는 것이다. 메서드의 매개변수와 인자의 관계와 비슷하다.

메서드에 필요한 값을 메서드 정의 시점에 미리 결정

void method1(){
	println("hello")
	
	}
  • 메서드에 필요한 값을 이렇게 메서드 정의 시점에 결정하게 되면 , 이 메서드는 오직 “hello”라는 값만 출력할 수 있다.
    • 하지만 매개변수를 넣는다면 ?
void method(String param){
	println(param)

}

void main(){
	method2("hello")
	method2("hi")

}

제네릭의 타입 매개변수와 타입 인자

제네릭도 앞서 설명한 메서드의 매개변수와 인자의 관계와 비슷하게 작동한다.

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

차이가 있다면 메서드의 매개변수는 사용할 값에 대한 결정을 나중으로 미루는 것이고, 제네릭의 타입 매개변수는 사용할 타입에 대한 결정을 나중으로 미루는 것이다.

GenericBox

  • String → GenericBox
  • Integer → GenericBox

Reference

인프런 김영한님의 자바강좌 + 나의 뇌



© 2022. by taewoo

Powered by taewoo