Java | Generic (1) <T>
Generic
Generic Programming: 어떤 값이 하나의 참조 자료형이 아닌
여러 참조 자료형을 사용할 수 있도록 프로그래밍하는 것
- 여러 개의 참조 자료형을 사용할 수 있도록 할 수 있고,
특정 자료형만 사용할 수 있도록 제한할 수도 있음 - 참조 자료형이 변환될 때 이에 대한 검증을 컴파일러가 하므로 안정적임
- 컬렉션 프레임워크도 많은 부분 제너릭으로 구현
배경
컬렉션에는 모든 자료형이 Object형으로 변환되어 저장되기 때문에
저장된 데이터를 불러올 때 자료형을 각각 지정해주어야 하는 문제가 발생
따라서 처음부터 저장할 자료형을 지정함으로써 편의성을 추구
특징
- 특정 자료형의 값만 입력 받아서 저장, 조회, 계산, 출력을 가능하게 함
- 멤버 변수, 메소드 매개변수에도 제너릭 부여 가능
- 기본 자료형은 사용 불가
- 컬렉션에 지정된 자료형으로만 데이터 저장 가능
컬렉션에는 객체만 저장 가능하기 때문에 클래스형 및 Wrapper 클래스만 지정 가능 - 컬렉션 내부의 데이터를 꺼내올 때 일일이 형 변환할 필요가 없어짐
→ 유지보수에 용이
종류
- < T > : Type, 클래스 설계시
- < E > : Element, List 컬렉션에 사용시
- < K, V > : Key-Value, Map 컬렉션에 사용시
- < ? > : 메소드 매개변수에만 사용
매개변수의 자료형을 < ? >로 정의하고 내부에서는
Object(또는 해당 클래스형)를 사용해서 모든 자료형의 매개변수를 처리할 수 있음
※ 실제로 기능에 차이가 있는 것은 아니고, 사용 위치에 따라 분류되는 것이며
T대신 A나 B와 같은 임의의 문자도 사용 가능 (? 제외)
< > 연산자
< >: 다이아몬드 연산자라고 하며
자료형을 <> 안의 클래스형으로 지정함
컬렉션<객체 종류> 컬렉션 객체명 = new 컬렉션<객체 종류>();
// Vector<String> v = new Vector(); → v 에 String 객체만 저장 가능
// 생성자() 앞의 <객체 종류> 는 생략 가능
※ Map 인터페이스 구현 클래스들은 키-값 쌍으로 데이터를 관리하기 때문에
2개의 객체 종류 명시 < key 객체 종류1, value 객체 종류2>
< T > Generic 클래스
- T: 자료형 매개변수(type parameter), 어떤 자료형도 사용할 수 있음을 나타내며
실제로 사용할 때는 하나의 자료형에 맞춰서 사용할 수 있도록 함 - T는 컴파일할 때 Object 클래스로 변환됨
- 클래스 이름을 '클래스명< T >' 로 정의하고 나중에 클래스를 사용할 때
T 위치에 실제 사용할 자료형을 지정 - 클래스의 각 메소드에서 해당 자료형이 필요한 부분에 모두 T를 사용하여 구현
- static 변수와는 함께 사용할 수 없음
static은 인스턴스의 제너릭 자료형이 결정되기 전에 생성되기 때문에
static 변수의 자료형이나 static 메소드 내부 변수의 자료형으로는 T 사용 불가
< T > Generic 클래스 구현 형식
// 클래스 정의
class 클래스명<T> {
// 멤버 변수 선언
T v[];
// setter 메소드
public void setV(T...v){
this.v = v;
}
// getter 메소드
public T[] getV(){
return v;
}
}
※ 멤버 변수와 메소드는 임의로 설정하였으며 자료형 지정을 위와 같은 형식으로 한다는 것
예제
T 자료형 배열에 값을 입력하고 출력하는 프로그램 작성
GenericEX.java
GenericEx 클래스를 담은 파일
package j200210;
public class GenericEx<T> {
// 멤버 변수
// String v[]; Double v2[]; Integer v3[];
T v[];
// setter, 전달된 인자들이 배열로 변수에 저장됨
public void setV(T... n) {
v = n;
}
/*
* public void setV(Double... n) { v2 = n; }
*
* public void setV(Integer... n) { v3 = n; }
*/
// getter
public T[] getV() {
// v[] 출력, 확장 for문
for (T s : v) {
System.out.println(s);
}
// v[] 반환
return v;
}
}
※ 자료형마다 멤버 변수, 메소드를 따로 만들 필요가 없어지고
T(type parameter)로 정의한 뒤에 객체 생성 후 메소드 호출시 자료형에 맞춰 사용
GenericExMain.java
GenericEX 클래스 객체 생성 후 메소드 호출을 위한 파일, main() 포함
package j200210;
public class GenericExMain {
public static void main(String[] args) {
// String 자료형만 처리하는 GenericEx 클래스 객체 생성
GenericEx<String> geStr = new GenericEx();
// geStr 객체에서 메소드 호출
geStr.setV("홍길동", "이순신", "세종대왕");
geStr.getV();
/*
홍길동
이순신
세종대왕
*/
// Double형만 처리하는 객체 생성
GenericEx<Double> geDbl = new GenericEx();
geDbl.setV(1.2, 2.4, 3.5);
geDbl.getV();
/*
1.2
2.4
3.5
*/
// Integer형만 처리하는 객체 생성
GenericEx<Integer> geInt = new GenericEx();
geInt.setV(1, 2, 3);
geInt.getV();
/*
1
2
3
*/
}
}
※ 객체 생성시 자료형을 지정해준 뒤 동일한 메소드를 호출하면 객체의 자료형에 맞게 메소드가 실행됨
제너릭의 개요와 <T>의 사용법에 대해 알아보았습니다.
<T>를 사용하면 여러 자료형을 처리해야하는 클래스를 보다 편리하게 작성할 수 있으면서도
객체 생성시 자료형을 지정하면 일정한 자료형에 대해 클래스 메소드를 호출할 수 있게 되므로
보다 편리하고 유연한 프로그래밍이 가능해진다고 할 수 있겠습니다.