Generic이란??
클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법
class Person<T> {
public T info;
}
public class GenericDemo {
public static void main(String[] args) {
Person<String> p1 = new Person<String>();
Person<StringBuilder> p2 = new Person<StringBuilder>();
}
}
T 는 info 필드의 데이터 타입입니다.
Person 클래스를 정의하는 시점에서는 info의 데이터 타입을 명시적으로 지정하지 않고 있다가
Person을 인스턴스화 할때 <> 안에 구체적인 데이터 타입인 <String>을 언급하면 <T>는 String이 되고
info의 데이터 타입은 String을 갖게 된다는 뜻입니다.
그럼 자연스럽게 인스턴스를 담아낼 수 있는 p1의 데이터 타입 역시 String이 됩니다.
Generic을 이용해서 두 개의 데이터 타입을 만들어봤습니다.
하나는 Info의 데이터 타입이 String인 것이고
또 다른 하나의 Info의 데이터 타입이 StringBuilder인 것 입니다.
Generic을 사용하면 얻는 이점
- 컴파일시 강한 타입 체크를 할 수 있습니다.
- → 컴파일시에 미리 타입을 강하게 체크해서 사전에 에러를 방지합니다.
- 타입변환을 제거할 수 있습니다.
List list = new ArrayList();
list.add("Hello"); //실제 저장하는건 String이지만 내부적으로 저장은 object로 저장
String str = (String) list.get(0);
// 그래서 호출시 object 타입으로 반환이 된다.
// 그래서 이런 점을 방지하고자 앞에 (String)을 붙혀줌으로 강제 타입변환이 필요하다
위 처럼 사용하면 두번의 타입변환이 생깁니다.
처음 list.add(”hello”); 을 String으로 저장이 될 때 그리고
(String) list.get(0); 으로 찾아올 때 Object 타입이 String으로 타입 변환이 됩니다.
그런데 Generic을 사용하게 되면 아래 처럼 코드가 바뀝니다.
List<String> list = new ArrayList<String>();
list.add("hello");
String str = list.get(0);
List<String> list 는 객체를 저장할 수 있는 컬렉션인 List에 String만 저장한다는 의미입니다.
구현 객체 new ArrayList<String>(); 에도 String 만 받겠다는 의미입니다.
list.add(”hello”);에 String을 주게 되면 내부에 저장될 때도 String으로 저장됩니다.
만약 String이 아니라 다른 타입이 들어오게 되면 컴파일 에러가 발생합니다.
그렇기 때문에 매개값을 줄때도 String으로 주고 내부 저장값도 String으로 저장되기 때문에
자동 타입변환이 발생하지 않습니다.
그리고 저장된 객체를 찾아오는 get이라는 메서드를 사용할때도 String 타입으로 바로 나옵니다.
위 두 코드를 비교하면 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 집니다.
Generic의 사용
// 클래스
public class ClassName <T> { ... }
// 인터페이스
public Interface InterfaceName <T> { ... }
// 제네릭 타입을 두 개 이상 사용하는 경우
public class MultiGeneric <K, V> { ... }
클래스나 인터페이스에 선언한 경우와 제네릭 타입을 두 개 이상 사용하는 경우입니다. 이때 T, K, V 타입은 해당 블록 {...} 안에서까지 유효합니다.
타입 변수**(Type Variable)**
기호의 종류만 다를 뿐 '임의의 참조형 타입'을 의미한다는 것은 모두 같으며, 상황에 맞게 의미 있는 문자를 선택해서 사용합니다.
T : Object <T>
E : Element <E>
K : Key <K>
V : Value <V>
N : Number <N>
Generic 용어
class Box<T> { }
//지네릭 클래스 선언
Box<String> b = new Box<String>();
Box<TV> c = new Box<TV>();
// 객체를 만들때마다 타입을 바꿀 수 있습니다.
Box<T> : Generic 클래스. ‘T의 Box’ 또는 ‘T Box’ 라고 읽습니다.
T : 타입 변수 또는 타입 매개변수.
Box : 원시타입(raw type)
<String>, <TV> : parameterized type, 매개변수화된 타입
Generic 타입과 다형성
다형성 : 하나의 참조변수로 여러 타입의 객체를 참조하는 것
- 참조 변수와 생성자의 parameterized type은 일치해야 합니다.
ArrayList<TV> list = new ArrayList<TV>(); // ok, 일치
ArrayLisy<Product> list = new ArrayList<TV>();// 에러, parameterized type 불일치
- Generic 클래스간의 다형성은 성립합니다 (parameterized type은 일치!!)
List<TV> list = new ArrayList<TV>(); // ok, 다형성, ArrayList가 List를 구현
List<TV> list = new LinkedList<TV>(); // ok, 다형성, LinkedList가 List를 구현
제한된 Generic 클래스
- extends로 대입할 수 있는 타입을 제한합니다
class FruitBox<T extneds Fruit> { // Fruit의 자손만 타입으로 지정 가능
ArrayList<T> list = new ArrayList<T>();
}
FruitBox<Apple> appleBox = new FruitBox<Apple>(); // ok
FruitBox<Toy> toyBox = new FruitBox<Toy>(); // 에러, toy는 Fruit의 자손x
타입 T만 있으면 모든 타입이 가능했는데 extends Fruit이라는 제한 조건을 줌으로서
Fruit의 자손만 대입가능합니다.
- 인터페이스인 경우에도 extends를 사용합니다.
interface Eatable { }
class FruitBox<T extends Eatable> { }
Generic의 제약
타입 변수에 대입은 인스턴스 별로 다르게 가능합니다.
Box<Apple> appleBox = new Box<Apple>(); // ok, Apple 객체만 저장 가능
Box<Grape> grapeBox = new Box<Grape>(); // ok, Grape 객체만 저장 가능
- static 멤버에 타입 변수 사용 불가능합니다
class Box<T> {
static T item; // 에러
static int compare(T t1, T t2) { /*생략*/ } // 에러
}
→ Box 클래스가 인스턴스가 되기 전에 static은 메모리에 올라가는데 이 때 item의 타입인 T가 결정되지 않기 때문에 위와 같이 사용할 수 없는 것이다.
- 객체, 배열 생성할 때 타입 변수 사용이 불가능합니다. (타입 변수로 배열 선언은 가능!)
class Box<T> {
T[] itemArr; // ok, T타입의 배열을 위한 참조변수
....
T[] toArray() {
T[] tmpArr = new T[itemArr.length] // 에러, 지네릭 배열 생성불가
....
}
new 다음에 T가 오면 안된다!
new 연산자 뒤에 타입은 확정되어 있어야 하는데 T는 어떤 타입이 올지 모르기 때문에 사용 불가능합니다.
와일드 카드 <?>
- 하나의 참조변수로 대입된 타입이 다른 객체를 참조 가능!
ArrayList<? extemds Product> list = new ArrayList<TV>(); // ok
ArrayList<? extemds Product> list = new ArrayList<Audio>(); // ok
ArrayList<Product> list = new ArrayList<TV>(); //에러, parameterized type불일치
<? extends T> : 와일드 카드와 상한 제한. T와 그 자손들만 가능
<? super T> : 와일드 카드와 하한 제한. T와 그 조상들만 가능
<?> : 제한 없음, 모든 타입이 가능 <? extends Object>와 동일
'Programming > Java, Spring' 카테고리의 다른 글
[JAVA]람다식이란? / 람다식의 특징 / Lambda Expression (0) | 2022.09.25 |
---|---|
[Spring] 스웨거 어노테이션 / Swagger 2.0 vs Swagger 3.0 차이 (0) | 2022.09.22 |
[Spring] JSP & Servlet / JSP와 Servlet의 역할 (0) | 2022.06.17 |
[Spring] MVC (Model, View, Controller) 패턴이란?? (0) | 2022.06.15 |
[JAVA] 인터페이스란?? 인터페이스의 작성, 구현 / 인터페이스의 상속 / 인터페이스의 다형성 / 인터페이스의 장점 (0) | 2022.06.04 |