개발 일지/Java

[Java] 제네릭(Generic)

미숫가루설탕많이 2023. 1. 4. 12:26

 자바 프로그래밍에서 제네릭(generic)이란, 데이터의 타입을 일반화한다는 것을 의미한다.

 

 다양한 타입의 데이터를 저장할 수 있는 객체를 만들고자 한다면, 각 타입별로 클래스를 따로 생성해야 하지만 제네릭을 사용하면 단 하나의 클래스만으로 모든 타입의 데이터를 저장할 수 있는 인스턴스를 만들 수 있다.

 

 제네릭은 클래스와 메서드에 다음과 같은 방법으로 선언할 수 있다.

class Basket<T> {
    private T item;

    public Basket(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }

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

 

 위 코드에서 사용된 T는 타입 변수이며, 임의의 참조형 타입을 의미한다. 여기서 T에 String을 입력한다면 Basket 클래스 내의 T가 모두 String으로 치환되는 것처럼 동작한다. 마찬가지로 int의 래퍼 클래스 Integer을 입력하면 T가 모두 Integer로 치환되는 것처럼 동작한다.

 

 꼭 'T'뿐만 아니라 다른 문자를 사용해도 상관없고 여러 개의 타입 변수는 쉼표(,)로 구분하여 명시할 수 있다.

 

 다음은 자주 사용하는 문자이다.

  • T : Type
  • K : Key
  • V : Value
  • E : Element
  • N : Number
  • R : Result

 

 제네릭은 클래스나 메서드의 코드를 작성할 때, 타입을 구체적으로 지정하는 것이 아니라 추후에 지정할 수 있도록 일반화해두는 것을 의미한다. 즉, 작성한 클래스 또는 메서드의 코드가 특정 데이터 타입에 얽매이지 않게 해 둔 것이다.

 

 

 

 

제네릭 클래스를 정의할 때 주의할 점

 

 제네릭 클래스에서 타입 매개변수를 임의의 타입으로 사용할 수 있다. 이 때, 클래스 변수에는 타입 매개변수를 사용할 수 없다.

 

 클래스 변수는 모든 인스턴스가 공유하는 변수이기 때문에 만약, 클래스 변수에 타입 매개변수를 사용할 수 있다면 클래스 변수의 타입이 인스턴스별로 달라지게 된다. 즉 Basket<String>으로 만든 인스턴스와 Basket<Integer>로 만든 인스턴스가 공유하는 클래스 변수의 타입이 서로 달라져서 클래스 변수를 통해 같은 변수를 공유하는 것이 아니게 된다. 따라서 static이 붙은 변수 또는 메서드에는 타입 매개변수를 사용할 수 없다.

 

 

 

 

제네릭 클래스 사용

 

  • 제네릭 클래스를 인스턴스화할 때에는 의도하고자 하는 타입을 지정해줘야 한다.

  • 타입 매개변수에 치환될 타입으로 기본 타입을 지정할 수 없다. 만약 int, double과 같은 원시 타입을 지정해야 하는 경우 Integer, Double과 같은 래퍼 클래스를 활용한다.
  • 제네릭 클래스를 사용할 때에도 다형성을 적용할 수 있다.

 

 

 

 

제네릭 메서드

 

  • 제네릭 메서드의 타입 매개변수 선언은 반환타입 앞에서 이루어지며, 해당 메서드 내에서만 선언한 타입 매개변수를 사용할 수 있다.
  • 제네릭 메서드의 타입 매개변수는 제네릭 클래스의 타입 매개변수와 별개의 것이다.

  • 클래스 타입 매개변수와 달리 메서드 타입 매개변수는 static 메서드에서도 선언할 수 있다.

  • 제네릭 메서드는 메서드가 호출되는 시점에서 제네릭 타입이 결정되므로, 제네릭 메서드를 정의하는 시점에서는 실제 어떤 타입이 입력 되는지 알 수 없기 때문에 length()와 같은 String 클래스의 메서드는 제네릭 메서드를 정의하는 시점에 사용할 수 없다. 하지만 모든 자바 클래스의 최상위 클래스인 Object 클래스의 메서드는 사용 가능하다.

 

 

 

 

와일드카드

 

 자바의 제네릭에서 와일드카드는 어떠한 타입으로든 대체될 수 있는 타입 파라미터를 의미하며, 기호 ?로 와일드카드를 사용할 수 있다.

 

 일반적으로 와일드카드는 extends와 super 키워드를 조합해서 사용한다.

<? extends T>
<? super T>

 

  •  <? extends T>는 와일드카드에 상한 제한을 두는 것으로, T와 T를 상속받는 하위 클래스 타입만 타입 파라미터로 받을 수 있도록 지정한다.

  • <? super T>는 와일드카드에 하한 제한을 두는 것으로, T와 T의 상위 클래스만 타입 파라미터로 받도록 한다.

  • extends 및 super 키워드와 조합하지 않은 와일드카드(<?>)는 <? extends Object>와 같다. 즉, 모든 클래스 타입을 타입 파라미터로 받을 수 있다.

'개발 일지 > Java' 카테고리의 다른 글

[Java] 예외 처리(Exception Handling)  (0) 2023.01.04
[Java] 에러(Error)  (0) 2023.01.04
[Java] 열거형(enumerated type, enum)  (0) 2023.01.04
[Java] 인터페이스(Interface)  (0) 2023.01.02
[Java] final 키워드  (0) 2023.01.02