본문 바로가기
Study

[Java] 제네릭(Generic)

by jisayDeveloper 2023. 10. 27.
728x90
반응형
SMALL

자바(Java)는 객체지향 프로그래밍 언어로, 타입 안정성(type safety)을 보장하며 다양한 데이터 유형을 다룰 수 있는 강력한 도구인 제네릭(Generic)을 제공합니다. 제네릭은 코드의 재사용성과 안정성을 높이는데 중요한 역할을 합니다. 이번 포스팅에서는 Java의 제네릭에 대해 개념적으로 소개하고, 사용법과 이점에 대해 알아보겠습니다.

 

제네릭(Generic)이란?

자바에서는 '클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법'을 의미합니다. 제네릭을 사용하면 클래스, 인터페이스 및 메소드를 정의할 때 어떤 데이터 타입이 사용될 것인지 미리 지정하지 않고, 실행 시에 유연하게 데이터 타입을 결정할 수 있는데 이는 다양한 데이터 타입을 다룰 때 중복 코드를 줄이고, 코드의 가독성과 유지보수성을 향상시킵니다.

 

보통 제네릭은 아래 표의 타입들이 많이 쓰입니다.

타입 설명
<T> Type
<E> Element
<K> Key
<V> Value
<N> Number

꼭 한글자일 필요도 없고 설명과 일치할 필요도 없습니다.  <DTO> 이런 식으로 다른 사람이 봤을때 알아볼 수 있게만 하면 되는 암묵적인 룰입니다.

 

제네릭 클래스 (Generic Class)  

제네릭 클래스는 클래스 내부에서 사용할 데이터 타입을 런타임이 아닌 컴파일 시에 지정할 수 있게 해줍니다.

예를 들어, 제네릭 클래스를 사용하여 배열, 리스트, 스택, 큐 등 다양한 데이터 구조를 만들 수 있습니다.

public class GenericBox<T> {
    private T item;

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

    public T getItem() {
        return item;
    }
}

GenericBox 클래스는 T라는 타입 매개변수를 사용하여 제네릭 클래스를 정의합니다.

이 클래스를 사용할 때, 실제 데이터 타입을 T의 자리에 대입하여 객체를 생성할 수 있습니다. 

 

사용한 예제를 보면

class GenericBox<T> {
    private T item;

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

    public T getItem() {
        return item;
    }
}
public class Main{
    public static void main(String[] args) {

        GenericBox<Integer> intBox = new GenericBox<>();
        intBox.setItem(42);
        Integer value = intBox.getItem();

        System.out.println("value: " + value);

        GenericBox<String> strBox = new GenericBox<>();
        strBox.setItem("jisay");
        String strValue = strBox.getItem();

        System.out.println("strValue: " + strValue);

    }
}

객체를 생성할 때 타입을 지정하고 콘솔 창에 출력해보면

value: 42
strValue: jisay

에러 없이 잘 출력됩니다. 

※ 정수형 타입은 제네릭 사용시 <int>가 아닌 <Integer>를 써야합니다. 그 이유는 

Java에서는 제네릭 타입을 사용할 때 기본 데이터 타입(primitive data type)을 직접적으로 사용할 수 없기 때문에 기본 데이터 타입을 래퍼 클래스(wrapper class)로 감싸서 사용해야 합니다. 

 

제네릭 인터페이스 (Generic Interface) 

 

제네릭 인터페이스는 인터페이스에서도 동일한 타입 매개변수를 사용할 수 있게 합니다. 예를 들어, List 인터페이스는 다양한 데이터 타입을 다루기 위한 제네릭 인터페이스입니다.

public interface List<T> {
    void add(T element);
    T get(int index);
}

제네릭 인터페이스를 구현하는 구체 클래스에서 실제 데이터 타입을 결정합니다.

 

사용한 예제를 보면

interface List<T> {
    void add(T element);
    T get(int index);
}

class MyList<T> implements List<T> {
    private T[] elements;
    private int size;

    public MyList(int size) {

	//생성자는 리스트의 초기 크기를 매개변수 size로 받아 elements 배열을 해당 크기로 초기화합니다.
        elements = (T[]) new Object[size];
    }

    @Override
    public void add(T element) {
    
	//size 변수를 사용하여 배열의 빈 위치에 요소를 추가하고 size를 증가시킵니다.
        if (size < elements.length) {
            elements[size] = element;
            size++; 
            
        }
    }

    @Override
    public T get(int index) {

	//지정된 인덱스에 있는 요소를 반환합니다.
        return elements[index];
    }

    public int size() {

	//리스트의 현재 크기를 반환합니다.
        return size;
    }
}

public class Main{
    public static void main(String[] args) {

        MyList<Integer> myList = new MyList<>(10);
        myList.add(42);
        myList.add(27);
        
        for(int i = 0; i < myList.size(); i++) {
            System.out.println("myList : "+myList.get(i));
        }
    }
}

 

콘솔창을 확인해보면

myList : 42
myList : 27

잘 출력되는 걸 확인 할 수 있습니다.

 

제네릭의 장점

  • 타입 안정성: 제네릭을 사용하면 컴파일 시에 타입 오류를 잡을 수 있어 런타임 에러를 방지합니다.
  • 코드 재사용성: 제네릭을 사용하면 다양한 데이터 타입에 대해 재사용 가능한 코드를 작성할 수 있어 중복을 줄입니다.
  • 가독성 향상: 제네릭을 사용하면 코드가 보다 읽기 쉽고 이해하기 쉬워집니다.
  • 유지보수성 향상: 제네릭을 사용하면 코드를 더 견고하게 만들어 유지보수를 용이하게 합니다.

마무리

제네릭은 Java에서 강력한 기능 중 하나로, 타입 안정성과 코드의 재사용성을 높이는데 중요한 역할을 합니다. 제네릭 클래스, 인터페이스, 메서드를 효과적으로 활용하여 프로그램을 개발할 때 더 안정적이고 유연한 코드를 작성할 수 있습니다. Java의 제네릭은 모던 자바 프로그래밍의 핵심 기술 중 하나이므로, 이를 잘 이해하고 활용하는 것이 중요합니다.

728x90
반응형
LIST