제네릭(Generic)

jiiiiiiiArchive.·2025년 1월 15일

🤯지식주머니🤯

목록 보기
66/98

모든 객체를 Object 타입으로 처리한 결과이다.
ArrayList에 다양한 타입의 데이터를 저장할 수 있지만 데이터를 꺼내 올 때마다 명시적으로 타입 캐스팅이 필요하다.

import java.util.*;

public class Main {
    public static void main(String[] args) {
      ArrayList list = new ArrayList();
      list.add("Hello");
      list.add(123);

      // 데이터를 꺼낼 때 타입 캐스팅이 필요
      String str = (String) list.get(0);
      Integer num = (Integer) list.get(1);
    }
}


=> 이 경고는 컴파일러가 raw 타입(ArrayList)을 사용했기 때문에 발생한다.

그렇다면 다음 예시를 보겠다.

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add("Hello"); // String 타입 추가
        list.add(123);     // Integer 타입 추가

        String str1 = (String) list.get(0);
        String str2 = (String) list.get(1);

        System.out.println(str1);
        System.out.println(str2);
    }
}

결과가 어떻게 될까 ?

오류가 발생한다.

  1. list.add(123)은 Interger 타입의 객체를 추가하고,
  2. list.get(1)으로 123을 꺼내올 때 이를 String으로 강제 형변환하려고 시도했지만
  3. 123은 실제 타입이 Integer이므로 변환이 불가능하고
  4. ClassCastException이 발생하게 된다.

Integer형 배열, String형 배열 등 배열에 포함되는 원소의 타입마다 추가, 삭제, 정렬과 같은 함수를 정의하고 사용하는 것은 비효율적이라고 생각이 들었다.
또한 어떤 새로운 자료구조를 만드려고 할 때 많은 타입을 지원하고 싶다면 각 타입에 대한 클래스 하나하나 각자 만드는 것도 비효율적이다.

그래서 나타난 ★제네릭★

제네릭 ?
사전적 의미로는 '일반적인'이다.
일반적인 ? 잘 이해가 되지 않는다.

그래서 찾아보았다.
데이터의 타입을 일반화한다.
클래스나 메서드 정의 시 일반화하여 사용할 데이터 타입을 컴파일할 때 미리 지정.

...

이라고 하는데 쉽게 내가 이해할 수 있게 정리하자면
"데이터 형식에 의존하지 않고 하나의 값이 여러 다른 데이터 타입들을 가질 수 있도록 하는 방법"
이다.

흔히 쓰는 ArrayList, LinkedList 등을 생성할 때
객체<타입> 객체명 = new 객체<타입>(); 과 같이 생성하는 것처럼

ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<String> list2 = new ArrayList<Integer>();
 
LinkedList<Double> list3 = new LinkedList<Double>():
LinkedList<Character> list4 = new LinkedList<Character>();

<> 괄호 안에 들어가는 타입을 지정해준다.

제네릭은 클래스 내부에서 지정하는 것이 아니라 외부에서 사용자에 의해 지정된다.
특정 타입을 미리 지정해주는 것이 아닌 필요해 의해 지정할 수 있도록 하는 일반 타입이다.

선언 및 생성

  • 클래스 또는 인터페이스 이름 뒤에 <> 기호를 추가하고 안에 타입 파라미터를 입력한다.
public class 클래스명<T> { ... }
public interface 인터페이스명<T> { ... }

사용방법

예시 코드

  • 제네릭 타입 변수를 사용하는 클래스
// T는 제네릭 타입 변수
class Box<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) {
        // Box 클래스의 인스턴스를 String 타입으로 생성
        Box<String> stringBox = new Box<>();
        stringBox.setItem("Hello, Generics!");
        String str = stringBox.getItem();
        System.out.println("String Box: " + str);

        // Box 클래스의 인스턴스를 Integer 타입으로 생성
        Box<Integer> intBox = new Box<>();
        intBox.setItem(123);
        Integer num = intBox.getItem();
        System.out.println("Integer Box: " + num);
    }
}

// 출력 결과
// String Box: Hello, Generics!
// Integer Box: 123
  • 제네릭 타입 변수를 사용하는 메서드
public class Main {
    // 제네릭 메서드: T 타입의 파라미터와 반환값을 사용
    public static <T> void printItem(T item) {
        System.out.println("Item: " + item);
    }

    public static void main(String[] args) {
        // 제네릭 메서드 호출
        printItem("Hello, Generics!"); // String 타입
        printItem(123);               // Integer 타입
        printItem(45.67);             // Double 타입
    }
}

// 출력 결과
// Item: Hello, Generics!
// Item: 123
// Item: 45.67

장점

  1. 타입 안정성 제공
  • 컴파일 시점에 타입을 체크하기 때문에 잘못된 타입을 사용할 경우 오류를 즉시 발견할 수 있다.
  • 런타임 오류(ClassCastException)를 방지한다.
List<String> list = new ArrayList<>();
list.add("Hello");
list.add(123); // 컴파일 오류: 타입이 맞지 않음
  1. 형변환 불필요
  • 데이터를 가져올 때 별도의 타입 캐스팅이 필요가 없어져 코드가 간결하고 가독성이 좋아진다.
List<String> list = new ArrayList<>();
list.add("Hello");
String str = list.get(0); // 타입 캐스팅 불필요
  1. 코드 재사용성 향상
  • 다양한 타입에서 재사용할 수 있는 범용 클래스를 설계할 수 있다.
class Box<T> {
    private T item;
    public void setItem(T item) { this.item = item; }
    public T getItem() { return item; }
}
  1. 의도 명확
  • 데이터의 타입을 명시적으로 지정해 코드를 읽는 사람이 어떤 타입의 데이터를 처리하는지 쉽게 이해할 수 있다.
List<Integer> intList = new ArrayList<>(); // Integer 타입 리스트임을 알 수 있음
  1. 런타임 오류 감소
  • 컴파일 시 타입 검사가 이루어져 런타입 오류 발생 가능성이 낮아진다.

주의 !!

제네릭은 배열 생성이 불가하다 !
왜 ? 타입 소거로 인해 런타임에 타입 정보를 보장할 수 없기 때문에

T[] array = new T[10]; // 컴파일 오류

개발자들은 귀찮은것을 싫어하는거같다...ㅋ

profile
이것저것 다 적는 기록장📚

0개의 댓글