위로
아래
제네릭
제네릭(Generics)
//기본형 선언
class 클래스이름<타입매개변수> {
필드;
메소드;
}
//제네릭 생성자 호출
제네릭클래스이름 <적용할타입(자료형)> 참조변수이름 = new 제네릭클래스이름 <>();
// 제네릭 클래스
public class 클래스이름 <T> { ... }
// 제네릭 인터페이스
public interface 인터페이스이름 <T> { ... }
// 제너릭 메소드
<타입매개변수> 반환타입 메소드이름 () { ... }
- 한 번의 정의로 여러 종류의 데이터 타입을 다룰 수 있도록 하는 방법 (하나의 코드를 다양한 타입의 객체에 재사용하는 객체 지향 기법)
- 자료형(타입)을 지정해주는 게 아니라, 변수로 사용한다.
- 클래스, 인터페이스, 메소드를 정의할 때 쓸 수 있다.
- 자료형을 클래스 내부에서 지정하는 것이 아니라, 외부에서 사용자에 의해 지정되는 것.
- <T> 타입은 해당 블럭까지만 유효하다.
- 다이아몬드 연산자 <> : 생성자에서 괄호 안을 생략하면, 문맥으로 추론해서 앞의 타입을 넣는다.
- 잘못된 자료형(타입)이 지정되어 오류가 날 수 있는 것을 미리 컴파일 단계에서 방지할 수 있다.
- 예시 : ArrayList<E> 형태로 클래스가 정의되어 있으면, 사용자가 데이터로 String을 사용할 때엔 ArrayList<String>, Integer를 사용할 때엔 ArrayList<Integer>로 사용할 수 있다.
용어
- 타입 매개변수(type parameter) : Human <T>에서 T
- 타입 인수(type argument) : Human <man>에서 man
- 매개변수화 타입 (parameterized type) : Human <man>
제네릭 불가 사항
- 기초 타입을 제네릭 인수로 사용 불가
- 정적 제네릭 타입 금지
- 제네릭 타입의 배열 생성 금지
제네릭 타입 매개변수
- E : 원소 (Element)
- K : 키 (Key)
- N : 숫자 (Number)
- T : 타입 (Type)
- V : 값 (Value)
제네릭 클래스 예시
더보기
// Men 클래스 파일
public class Men {
@Override
public String toString() {
return "남자입니다.";
}
}
// Women 클래스 파일
public class Women {
@Override
public String toString () {
return "여자입니다.";
}
}
// Humen 제네릭 클래스 파일
public class Humen <T>{
private T gender;
void setGender(T gender){
this.gender = gender;
}
T getGender(){
return this.gender;
}
}
// 메인 클래스 파일
public class CheckedGenderMain {
public static void main(String[] args) {
Humen <Men> m = new Humen<Men>();
Humen <Women> w = new Humen<>();
m.setGender(new Men());
w.setGender(new Women());
System.out.println(m.getGender());
System.out.println(w.getGender());
}
}
2중 제네릭 클래스 예시
더보기
// 제네릭 클래스
public class Entry <K,V> {
private K key;
private V value;
// 메인 클래스에서 Entry 클래스로 객체를 생성new Entry<String, Integer>()
//String key;
//Integer value;
//이렇게 선언했다고 봐도 된다
public Entry(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
}
// 메인 클래스
public class EntryDemo {
public static void main(String[] args) {
Entry<String, Integer> e1 = new Entry<>("김선달",20);
Entry<String, String> e2 = new Entry<>("기타", "등등");
//Entry<int,String> e3 = new Entry<>(30, "아무개")
System.out.println(e1.getKey()+" "+e1.getValue());
System.out.println(e2.getKey()+" "+e2.getValue());
}
}
제네릭 메소드 예시
자료형은 메소드에 들어온 매개변수의 타입으로 결정된다.
더보기
// 제네릭 메소드를 정의하는 클래스 Utils
public class Utils {
static public <T> void showArray(T[] arr) {
for(T x:arr) {
System.out.printf("%s",x);
}
System.out.println();
}
static public <T> T getLast(T[] arr) {
return arr[arr.length-1];
}
}
// 메인 메소드
public class GenMethod1Demo {
public static void main(String[] args) {
Integer[] ia = {1,2,3,4,5};
Character[] ca = {'a','b','c','d','e'};
Utils.showArray(ia); // 결과 12345
Utils.<Character>showArray(ca); // 결과 abcde
System.out.println(Utils.<Integer>getLast(ia)); // 결과 5
//<자료형>을 줘도 되고 안 줘도 된다.
}
}
상속 받은 제네릭 메소드 예시 (제한된 제네릭 메소드)
상속을 이용하면 해당 타입과 자식 타입들만 매개변수로 들어올 수 있도록 제한된다.
더보기
// 제네릭 메소드가 들어 있는 클래스
public class Utils2 {
// 제네릭 타입 T가 Number클래스를 상속받고 있다.
// Number 클래스의 자손 타입들만 제네릭 타입 매개변수에 들어올 수 있다.
static public <T extends Number> void showArray(T[] arr) {
for(T x:arr) System.out.printf("%s",x);
}
}
// 메인 클래스
public class GenMethod2Demo {
public static void main(String[] args) {
Integer[] ia = {1,2,3,4,5};
Double[] da = {1.0,2.0,3.0,4.0,5.0};
Character[] ca = {'a','b','c','d','e'};
Utils2.showArray(ia); // 결과 12345
Utils2.showArray(da); // 결과 1.0 2.0 3.0 4.0 5.0
// Utils2.showArray(ca); // 문자형은 Number 클래스의 자손 타입 형태가 아니다
}
}