Generic Type(=제네릭 타입)

2025. 11. 28. 14:38·java

# 제네릭이란?

Java에서 제네릭은 코드를 재사용하기 쉽게 만들고 동시에 타입 안정성(type safety) 을 보장하기 위한 문법이다.
클래스나 메서드를 선언할 때 타입을 미리 정하지 않고 실제 사용할 시점에서 타입을 결정하는 형태로 동작한다.


제네릭은 <>(다이아몬드) 기호로 표현된다.

제네릭을 사용할 경우 컴파일 시점에서 타입을 보장할 수 있어 형변환 오류처럼 런타임에서 발생하는 문제를 방지할 수 있다.


# 제네릭을 사용하는 이유

타입 안정성(Type Safety)

제네릭을 사용하지 않으면 모든 값이 Object 형태로 저장된다.
이 경우 꺼낼 때 직접 캐스팅해야 하고 잘못된 타입으로 캐스팅하면 런타임 오류가 발생한다.

List list = new ArrayList();
list.add("hello");
list.add(3); // 서로 다른 타입 추가 가능 → 문제 발생 가능

String str = (String) list.get(0); // 캐스팅 필요
제네릭을 사용하면 컴파일러가 타입을 미리 검사하기 때문에 잘못된 타입의 객체가 들어가는 것을 방지한다.
List<String> list = new ArrayList<>();
list.add("hello"); // 타입 안정성 확보
String str = list.get(0); // 캐스팅 불필요

 

# 코드 재사용성(Code Reusability)

제네릭을 사용하면 하나의 코드로 여러 타입을 처리할 수 있다.
예를 들어 동일한 로직을 정수 리스트에도 사용할 수 있고 문자열 리스트에도 사용할 수 있다.

public static <T> void printList(List<T> lists) {
    for (T t : lists) {
        System.out.println(t);
    }
}

제네릭 기본 예제

package generic_;

import java.util.ArrayList;
import java.util.List;

public class GenericT {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("hello");

        String str = list.get(0);
    }
}​
제네릭을 사용하면 불필요한 캐스팅이 필요 없고 타입 오류도 컴파일 시점에 잡힌다.

# 제네릭 메서드를 이용한 코드 재사용

public static <T> void printList(List<T> lists) {
    for (T t : lists) {
        System.out.println(t);
    }
}
var intList = Arrays.asList(1, 2, 3);
var strList = Arrays.asList("A", "B", "C");

printList(intList);
printList(strList);
 
같은 코드로 여러 타입을 처리할 수 있어 재사용성이 크게 향상된다.

# 제네릭 실전 활용

제네릭은 특히 상속 구조가 있는 클래스들을 다룰 때 유용하다.

아래 예제는 Fruit의 하위 클래스인 Apple, Banana 등을 하나의 박스에서 다루기 위해 FruitBox<T> 제네릭 클래스를 만들었다.


Fruit → Apple / Banana 구조

class Fruit {
    public void consume() {
        System.out.println("Consuming a fruit!");
    }
}

class Apple extends Fruit {
    @Override
    public void consume() {
        System.out.println("Eating an Apple");
    }
}

class Banana extends Fruit {
    @Override
    public void consume() {
        System.out.println("Eating a Banana");
    }
}

제네릭 클래스: FruitBox<T extends Fruit>

class FruitBox<T extends Fruit> {
    private List<T> lists = new ArrayList<>();

    public void add(T fruit) {
        lists.add(fruit);
    }

    public T get(int index) {
        return lists.get(index);
    }

    public void consumeAll() {
        for (T t : lists) t.consume();
    }
}
💡 T extends Fruit

👉 Fruit 또는 그 자식만 추가할 수 있도록 타입을 제한
👉제네릭의 bounded type 활용 예

실행 예제

class Main {
    public static void main(String[] args) {
        FruitBox<Fruit> fruitBox = new FruitBox<>();

        fruitBox.add(new Apple());
        fruitBox.add(new Banana());

        fruitBox.consumeAll();
    }
}
출력: 
Eating an Apple Eating a Banana

 


구분 내용
목적 타입 안정성 확보 + 코드 재사용성 증가
문법 <> 다이아몬드 기호
동작 방식 컴파일 시점에 타입 검사
장점 캐스팅 불필요, 오류 예방, 유지보수 용이
실무 활용 API 응답 구조, 컬렉션, 유틸리티 클래스, 공통 모듈

'java' 카테고리의 다른 글

Stream  (0) 2025.11.28
Lambda Expression(=람다식)  (0) 2025.11.28
Abstract class(=추상화)  (0) 2025.11.28
Encapsulation(=캡슐화)  (0) 2025.11.28
Java 문법 – Overload vs Override  (0) 2025.11.28
'java' 카테고리의 다른 글
  • Stream
  • Lambda Expression(=람다식)
  • Abstract class(=추상화)
  • Encapsulation(=캡슐화)
차하비
차하비
chadev 님의 블로그 입니다.
  • 차하비
    chadev
    차하비
  • 전체
    오늘
    어제
    • 분류 전체보기 (47)
      • kubernetes, k8s (3)
      • docker (3)
      • cloud (6)
      • linux (12)
      • spring (7)
      • java (11)
      • error (4)
      • 자격증 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    진법
    docker
    KUBECTL
    k8s
    Kubernetes
    url
    Join
    객체지향
    restAPI
    Spring
    비트 연산
    OOP
    HTTP
    Java
    URI
    thread
    클래스
    monolithic
    모놀리식
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
차하비
Generic Type(=제네릭 타입)
상단으로

티스토리툴바