Java Generic - 실무에서의 관례

제네릭의 핵심은? 사용할 타입을 미리 결정하지 않는다는 것이다.
클래스 내부에 사용할 타입을 클래스로 정의하는 시점에 결정이 아닌 실제 생성 시점에 타입을 결정한다.

제네릭의 타입 매개변수 그리고 인자

제네릭 또한 메소드의 매개변수 인자의 관계가 비슷하다.
클래스를 정의할때에는 내부에서 사용할 타입을 미리 결정하지 않고 미래에 결정해 유연성을 챙긴다.
제네릭을 사용하지 않는 메소드의 매개변수 차이가 있다면 메소드의 매개변수는 "값"을 나중에 사용하고, 제네릭 타입은 매개변수 "타입"을 결정을 미루는 것이다.

  • 메소드: 매개변수 인자로 이용해 값을 전달한다.
  • 제네릭 클래스: 타입 매개변수와 타입 인자를 전달해 타입을 결정한다.

메소드로 필요한 값을 인자로 전달해 결정

void method(String param) {
    System.out.println(param);
}

void main() {
    method("Hello");
    method("Java");
}
  • 메소드에는 특정 값 없이 사용하는 시점(호출자)으로 사용을 미루는 것으로 볼 수 있다.
  • 메소드는 단순히 파라미터 String param 선언만하고, 호출자가 메소드를 사용할 때 값을 인자로 전달하였다. (Hello, Java)

메소드에서 기본 값을 설정하고 나중에 들어온 값부터 처리

void mathod(String param="Hello World") {
    System.out.println(param);
}

void main() {
    method("??Hello??");
    method();
}
  • 메소드 파라미터에서 Default 파라미터로 줄 수가 있다. 이렇게 한 경우 나중에 들어온 값을 우선으로 출력하지만 만약 값이 비어있는 경우 Default 값으로 출력하게 된다.

메소드로 인한 재사용성을 크게 증가시켜 코드를 고품질로 만들어낸다.

제네릭에서의 용어가 메소드의 매개변수, 인자를 그대로 사용하고 있다. 다만 값이 아닌 타입에서 결정되므로 앞에서 <T> 다이아몬드 안에 타입이 붙는 다는 특징을 기억해두자.


제네릭 정리

  • 제네릭 (Generic)
    • 프로그래밍에서 설정으로 많이 볼 수 있다. 범용이라는 영어 단어이다.
    • 특정 타입에 속하지 않고 범용적으로 사용할 수 있다는 의미이다.
  • 제네릭 타입 (Generic Type)
    • 제네릭 클래스, 제네릭 인터페이스 모두 제네릭 타입으로 불리오고 있다.
    • 클래스 또는 인퍼테이스 정의시 타입 매개변수에 사용하는 기능이다.
    • Class GenericBox<T> { ... } 모두 합쳐서 표현
  • 타입 매개변수 (Type Parameter)
    • 제네릭 타입과 메소드에 사용하는 변수로 실제 타입으로 대체한다.
    • GenericBox<T>
  • 타입 인자 (Type Argument)
    • 제네릭 타입을 사용시 실제 타입을 가리킨다.
    • 다이아몬드 안에 있는 것이 제네릭 인자다. GenericBox<String>

제네릭 명명 개발자 관례

개발자들과 제네릭을 사용 시 관례가 있다.
코드리뷰 등 다른 사람과 협업 시 많이 사용하므로 지켜주도록 한다.

제네릭 명명법

  • E - Element
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S, U, V ... - 2nd, 3rd... types

제네릭 기타 선언

한번에 여러 타입을 매개변수로 선언이 가능하다.

class Dic<K, V> {}

제네릭 기본형은 사용 불가

제네릭은 타입 인자로 기본형인 타입을 사용할 수 없다.(int, double..)
래퍼 클래스로 정의한 타입으로 사용하자 (Integer, Double...)

제네릭 원시 타입 - row Type

public class Main {
    public static void main(String[] args) {
        GenericBox<Integer> integerVal = new GenericBox<>();
        GenericBox obj = new GenericBox(); // Row Type
        integerVal.set(100);
        obj.set(300);
        Integer err = (Integer) obj.get();
        System.out.println(err); // 다운 캐스팅 인셉션 발생
    }
}

다음과 같이 다이아몬드를 사용하지 않은 것을 원시 타입 Row Type 이라한다.
물론 다이아몬드 사용하지 않아도 사용가능하지만 이럴 경우 타입이 Object으로 되어버린다.

되도록이면 다이아몬드<> 사용해서 원하는 타입을 지정해야한다.
꼭 Object로 사용해야 한다면 <Object> 로 명시해주도록 한다.

💡
원시 타입이 없어도 문제가 없으나, 과거 자바 하위 호환으로 유지하고 있다.