Generic 개념 정리

Generic Type 매개변수, 사용 주의사항
SHIN's avatar
Sep 06, 2024
Generic 개념 정리
💡
클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법 - 객체별 다른 타입의 자료가 저장될 수 있도록 함
ArrayList<String> list = new ArrayList<>(); // <> : generic // () : 타입명 기재 // -> 리스트 클래스 자료형의 타입 = String 타입으로 지정되어 문자열 데이터만 리스트에 적재 가능
 

1. 개념 예제

notion image
  • generi은 배열의 타입을 지정하듯 리스트 자료형 같은 collection class나 method에서 사용할 내부 데이터 타입을 parameter 주듯이 외부에서 지정하는 이른바 타입을 변수화 한 기능
💡
우리가 변수를 선언할 때 변수의 타입을 지정해주듯, generic은 객체(Object)에 타입을 지정해주는 것이라고 보면 된다
 

1-1. 수업 예제

// Generic = new하는 애가 처리 class Box<T> { T data; } public class App { public static <B> Box<?> test(B data) { Box<B> b = new Box(); b.data = data; return b; } public static void main(String[] args) { Box b = test(1); } }
 
 

Type Parameter 기호 네이밍

타입
설명
<T>
타입(Type)
<E>
요소(Element), Ex) List
<K>
키(Key), Ex) Map<k,v>
<V>
Return 값 또는 매핑 된 값 (Variable)
<N>
숫자 (Number)
<S, U, V>
2, 3, 4번째 선언된 타입
 

2. Generic Type 매개변수

notion image
  • 꺽쇠 괄호 안에 식별자 기호를 지정함으로써 파라미터화 가능
  • 이것을 마치 method가 매개변수를 받아 사용하는 것과 비슷하여 Generic의 타입 매개변수(parameter) / 타입 변수라고 부름
 
2-1. Type Parameter 정의
  • 이 타입 매개변수는 generic을 이용한 클래스나 메소드 설계 시 사용
class FruitBox<T> { List<T> fruits = new ArrayList<>(); public void add(T fruit) { fruits.add(fruit); } }
// generic 클래스 생성 후 인스턴스화 -> 파라미터를 지정해서 보내는 것처럼 생성 코드애서 꺽쇠 괄호 안에 // 지정해주고 싶은 타입명 할당 시, generic 클래스 선언문 부분으로 가서 타입 파라미터 T가 지정된 타입으로 // 모두 변환되어 클래스의 타입이 지정되게 되는 것 // generic 타입 매개변수에 정수 타입을 할당 FruitBox<Integer> intBox = new FruitBox<>(); // generic 타입 매개변수에 실수 타입을 할당 FruitBox<Double> intBox = new FruitBox<>(); // generic 타입 매개변수에 문자열 타입을 할당 FruitBox<String> intBox = new FruitBox<>(); // 클래스도 넣어줄 수 있음 (Apple 클래스가 있다고 가정) FruitBox<Apple> intBox = new FruitBox<Apple>();
 
2-2. 그림 예제 (generic 타입 전파)
notion image
  • <T> 부분에서 실행부에서 타입을 받아와 내부에서 <T> 타입으로 지정한 멤버들에게 전파하여 타입이 구체적으로 설정되는 것 → 구체화(Specialization)
 
 
2-3. Type Parameter 할당 가능 타입
  • generic에서 할당 받을 수 있는 타입은 Reference 타입 뿐 → int형, double형 같은 자바 원시 타입(Primitive Type)을 generic type parameter로 넘길 수 없음
// 기본 타입 int는 사용 불가 List<int> intList = new List<>(); // Wrapper 클래스로 넘겨줘야 함 (내부에서 자동으로 언박싱되어 원시 타입으로 이용됨) List<Integer> integerList = new List<>();
 
 
2-4. 복수 타입 Parameter
  • 타입 지정이 여러개 필요할 경우 2, 3개 얼마든지 생성 가능
  • generic 타입의 구분은 꺽쇠 괄호 안에서 쉼표(,)로 하며 <T, U>와 같은 형식을 통해 복수 타입 파라미터 지정 가능 (클래스 초기화 시 generic 타입을 2개 넘겨줘야 함)
import java.util.ArrayList; import java.util.List; class Apple {} class Banana {} class FruitBox<T, U> { List<T> apples = new ArrayList<>(); List<U> bananas = new ArrayList<>(); public void add(T apple, U banana) { apples.add(apple); bananas.add(banana); } } public class Main { public static void main(String[] args) { // 복수 generic 타입 FruitBox<Apple, Banana> box = new FruitBox<>(); box.add(new Apple(), new Banana()); box.add(new Apple(), new Banana()); } }
 

3. Generic 사용 주의사항

 
3-1. generic 타입의 객체는 생성 불가
class Sample<T> { public void someMethod() { // Type parameter 'T' cannot be instantiated directly T t = new T(); // new 연산자 뒤에 generic 타입 파리미터는 올 수 없음 } }
 
3-2. static 멤버에 generic 타입이 올 수 없음
class Student<T> { private String name; private int age = 0; // static 메서드의 반환 타입으로 사용 불가 // why? static 멤버는 클래스가 동일하게 공유하는 변수로서 generic 객체가 생성되기 전에, // 이미 자료 타입이 정해져 있어야 하기 때문 -> 논리적 오류 public static T addAge(int n) { } // static 메소드의 매개변수 타입으로 사용 불가 // public static void addAge(T n) { // } }
 
3-3. generic으로 배열 선언 주의점
// 기본적으로 generic 클래스 자체를 배열로 만들 수 없음 class Sample<T> { } public class Main { public static void main(String[] args) { Sample<Integer>[] arr1 = new Sample<>[10]; } } // Error - java: cannot create array with '<>'
// generic 타입의 배열 선언은 허용됨 // 위의 식과 차이점 : 배열에 저장할 Sample 객체의 타입 파라미터를 Integer로 지정함 // -> new Sample<Integer>() 인스턴스는 저장이 가능, new Sample<Stirng>() 인스턴스는 저장이 불가능 class Sample<T> { } public class Main { public static void main(String[] args) { // new Sample<Integer>() 인스턴스만 저장하는 배열을 나타냄 Sample<Integer>[] arr2 = new Sample[10]; // generic 타입을 생략해도 위에서 이미 정의했기 때문에 Integer 가 자동으로 추론 arr2[0] = new Sample<Integer>(); arr2[1] = new Sample<>(); // ! Integer가 아닌 타입은 저장 불가능 arr2[2] = new Sample<String>(); } }
Share article

SHIN