제네릭이란 무엇인가?

발행: (2026년 2월 12일 오후 08:00 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

Generics는 Java 5에서 도입된 기능으로, 다양한 데이터 타입을 다루는 클래스, 인터페이스 및 메서드를 만들 수 있게 해줍니다. 명시적인 형변환(cast)이 필요 없게 해주며, 컴파일 시점에 오류를 감지하는 데 도움을 줍니다.

Java 5 이전에 컬렉션은 모든 요소를 Object로 취급했습니다. 이 때문에 두 가지 문제가 발생했습니다:

  • 과도한 캐스팅: 리스트에서 값을 꺼낼 때마다 (String)과 같은 캐스트를 해야 했습니다.
  • 안전성 부족: String만 들어가야 할 리스트에 Integer가 삽입되는 것을 방지할 방법이 없어, 실행 시 오류가 발생했습니다.
// Código antigo
List lista = new ArrayList(); // Lista "crua" (Raw Type)
lista.add("Olá");
lista.add(10); // O compilador deixa passar!

// O erro só acontece aqui, quando o programa está rodando:
String texto = (String) lista.get(1); // ClassCastException!
// Código novo com Generics
List lista = new ArrayList<>();
lista.add("Olá");
// lista.add(10); // O compilador nem deixa compilar. Erro na hora!

String texto = lista.get(0); // Sem necessidade de cast manual.

타입 변수

Generics는 클래스와 메서드가 여러 타입의 객체에서 동작하도록 하며, 컴파일 시점의 안전성을 보장합니다 (compile‑time safety). 관례상, 이러한 제네릭 타입을 나타내기 위해 대문자를 사용합니다:

  • T: Type (제네릭 타입)
  • E: Element (컬렉션에서 사용)
  • K, V: Key, Value (맵에서 사용)

제네릭 클래스

제네릭 클래스는 T 로 표시되는 타입 매개변수를 사용하며, 이는 실제 타입을 위한 자리표시자 역할을 합니다.

// define que esta classe aceita um parâmetro de tipo
public class Caixa<T> {
    private T conteudo;

    public void guardar(T conteudo) {
        this.conteudo = conteudo;
    }

    public T abrir() {
        return conteudo;
    }
}

public class AulaGenerics {
    public static void main(String[] args) {
        // Caixa que só aceita Strings
        Caixa<String> caixaDeTexto = new Caixa<>();
        caixaDeTexto.guardar("Segredo");
        // caixaDeTexto.guardar(123); // Erro de compilação!

        // Caixa que só aceita Inteiros
        Caixa<Integer> caixaDeNumeros = new Caixa<>();
        caixaDeNumeros.guardar(100);
    }
}

T는 객체를 생성할 때 String, Integer 또는 다른 타입으로 대체됩니다.

Wildcards

wildcards (?)는 제네릭에서 알 수 없는 타입을 나타내며, 다양한 컬렉션 타입을 허용하는 메서드를 만드는 데 유용합니다.

  • ? – 모든 타입.
  • ? extends T (upper bounded) – T 혹은 T의 모든 서브타입을 허용합니다. 사용: 데이터를 읽기만 할 때.
  • ? super T (lower bounded) – T 혹은 T의 모든 슈퍼타입을 허용합니다. 사용: 데이터를 쓰기할 때.

실전 예제

import java.util.*;

public class Wildcards {

    // Aceita lista de Number OU QUALQUER SUBTIPO (Integer, Double...)
    // Só consigo LER com segurança (sei que tudo ali é Number)
    public static double somarLista(List lista) {
        double soma = 0;
        for (Number n : lista) { // Posso ler como Number
            soma += n.doubleValue();
        }
        // lista.add(10); // ERRO! Não posso adicionar nada (não sei se é lista de Double ou Integer)
        return soma;
    }

    public static void main(String[] args) {
        List inteiros = new ArrayList<>();
        inteiros.add(1);
        inteiros.add(2);

        List doubles = new ArrayList<>();
        doubles.add(1.5);
        doubles.add(2.5);

        // O método aceita ambos!
        System.out.println(somarLista(inteiros));
        System.out.println(somarLista(doubles));
    }
}

Type Erasure

Generics는 컴파일러를 위해서만 존재합니다. 컴파일이 끝난 후, Java는 (type erasure) 모든 제네릭 정보를 삭제하고 Object(또는 상한) 로 대체하며 자동으로 캐스트를 삽입합니다. 실행 시간에 ListList는 같은 클래스(List)입니다. 이 전략은 이전 Java 버전과의 호환성을 유지하기 위해 채택되었습니다.

0 조회
Back to Blog

관련 글

더 보기 »

Ollama, NGROK 및 LangChain 설정

markdown !Breno A. V.https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fu...