본문 바로가기
Web Technologies 🖥️/java

제네릭(Generic)을 써보고 싶어요 - JAVA

by dudefromkorea 2024. 1. 20.

아래 코드가 이해되시나요?

이해가 안 간다면

공부해 봅시다

 

"제네릭"

 

public class Generic<T> {
    private T content;

    public void setGeneric(T content) {
        this.content = content;
    }

    public T getGeneric() {
        return content;
    }

    public static void main(String[] args) {
        Generic<String> genericForStr = new Generic<>();
        genericForStr.setGeneric("Hello World");

        Generic<Integer> genericForInt = new Generic<>();
        genericForInt.setGeneric(123456);

        System.out.println("String: " + genericForStr.getGeneric());
        System.out.println("Integer: " + genericForInt.getGeneric());
    }
}

 

 

Generic 클래스의 타입 파라미터 T 가

다양한 타입을 처리할 수 있는 이유

사용된 파라미터 T

(보통 E, T, K ,V 를 많이 쓴다)

특정 타입에 국한되지 않고

어떤 타입이든 포용할 수 있는

"플레이스 홀더" 역할이기 때문

 

 

파라미터 T 의 타입이 결정되는 시점

제네릭을 사용하는 코드가 컴파일될 때

T 는 구체적인 타입으로 대체된다

 

Generic<String> 을 생성하면 T 는 String

Generic<Integer> 를 생성하면 T 는 Int 로 해석

 

따라서 Generic 인스턴스들은

자신의 타입 파라미터에 맞는 객체만을

저장하고 반환할 수 있기 때문에

타입 안정성이 보장된다

 

래퍼 클래스를 사용하는 이유

제네릭은 참조 타입만 파라미터로 사용 가능

기본형 타입은 제네릭의 파라미터로 사용 불가!!

 

래퍼 클래스를 사용할 경우

null 값을 허용할 수 있고

다양한 유틸리티 메소드를 사용할 수 있음

 

제네릭을 사용하는 이유

타입 안정성 보장

앞서 말했던 것처럼 오직 자신의 타입 파리미터에 맞는 객체만을

저장하고 반환할 수 있기 때문에 타입 안정성이 보장된다

코드 재사용성 증가

하나의 코드로 다양한 타입을 처리할 수 있기 때문에

코드 중복을 줄이고, 깔끔한 코드를 작성할 수 있다

타입 캐스팅 감소

제네릭을 사용할 경우 명시적인 타입 캐스팅이

필요 없어지므로 코드의 가독성과 유지 보수성이 향상된다

API 명확성

API 를 사용하는 개발자에게 명확한 타입 정보를 제공하여

API 에 대한 사용 방법을 더 명확하게 이해시킬 수 있다

 

주의사항

제네릭을 남발할 경우

코드가 복잡해지고 이해하기 어려운 코드가

된다는 것은 이미 유추했을 거라 생각한다

 

그렇다면 그 외에 중요한 주의사항으로는

 

컴파일 시점 제한(타입 소거)으로 인한 배열 사용 불가

제네릭은 타입 정보가 컴파일 시점에만 존재하고

런타임 시에는 타입 정보가 소거되므로

런타임에 타입 파라미터의 구체적인 타입을 알 수 없다

따라서 new T[] 와 같은 표현은 허용되지 않고

instanceof 와 같은 연산에도 영향을 준다

 

와일드카드

제네릭 타입의 범위를 보다 더 유연하게

사용하기 위해 사용하는 "와일드카드"

 

메소드의 파리미터, 리턴 타입, 변수 선언 등에서 사용하며

List < ? extends Number > 는 Number 또는 그 하위(Integer, Double)

List < ? super Integer > 는 Integer 또는 그 상위 클래스 객체를 가질 수 있다

바운디드 타입

마찬가지로 제네릭을 보다 유연하게

쓰기 위해 사용되는 "바운디드 타입"

 

클래스나 메소드를 정의할 때 사용되며

class Example < T extends Number> 로 하한을 지정하고

class Example < T super Integer> 로 상한을 지정할 수 있다

(와일드카드의 extends, super 설명 참조)

 

차이점

바운디드 타입은 타입 안정성에 중점을 두고,

와일드카드는 특정 타입에 대한 유연성과 범용성을 제공

728x90
반응형