제네릭이 갖는 의미는 '일반화'이며 그 대상은 자료형입니다.
ArrayList, LinkedList 등을 생성할 때 "객체<타입> 객체명 = new 객체<타입>();" 의 방식으로 사용되었습니다.
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<String> list2 = new ArrayList<Integer>();
LinkedList<Double> list3 = new LinkedList<Double>():
LinkedList<Character> list4 = new LinkedList<Character>();
제네릭도 이와 같이 <>안에 타입을 지정해 줍니다.
하지만, 위와 같이 한가지 타입만을 지원하는 자료구조를 만들고 싶지 않고 여러가지 타입을 지원하는 자료구조를 만들고 싶을떄 제네릭을 사용할 수 있습니다. 제네릭은 클래스 내부에서 지정하는 것이 아닌 외부에서 사용자에 의해 지정되는 것을 의미합니다. 자바에서 제네릭이 등장한 이후로 자료형에 의존적이지 않은 클래스를 작성할 수 있게 되었습니다.
제네릭은 원시 타입(primitive type)이 아닌 참조 타입(reference type)으로 사용해야 합니다.
1. 클래스 및 인터페이스 선언
public class ClassName <T> { ... }
public Interface InterfaceName <T> { ... }
기본적인 제네릭 타입의 클래스나 인터페이스의 경우 다음과 같이 선언합니다.
T타입은 해당 블록 {...}에서만 유효합니다.
예시)
public class ClassName <T, K> { ... }
public class Main {
public static void main(String[] args) {
ClassName<String, Integer> a = new ClassName<String, Integer>();
}
}
예시에서는 T는 String이 되고 K는 Interger가 됩니다.
제네릭은 타입을 지정할때 원시타입(primitive type)이 아닌 참조 타입(reference type)으로 선언해야합니다. 즉, int, double, char같은 타입은 올 수 없고 Interger, Double, String등으로 사용할 수 있습니다.
그리고 참조타입이 올 수 있다는것은 클래스나 인터페이스도 타입으로 올 수 있다는 것입니다.
public class ClassName <T> { ... }
public class Student { ... }
public class Main {
public static void main(String[] args) {
ClassName<Student> a = new ClassName<Student>();
}
}
2. 제네릭 클래스
제네릭 클래스 선언
// 제네릭 클래스
class ClassName<E> {
private E element; // 제네릭 타입 변수
void set(E element) { // 제네릭 파라미터 메소드
this.element = element;
}
E get() { // 제네릭 타입 반환 메소드
return element;
}
}
class prac2 {
public static void main(String[] args) {
ClassName<String> a = new ClassName<String>();
ClassName<Integer> b = new ClassName<Integer>();
a.set("10");
b.set(10);
System.out.println("a data : " + a.get());
// 반환된 변수의 타입 출력
System.out.println("a E Type : " + a.get().getClass().getName());
System.out.println();
System.out.println("b data : " + b.get());
// 반환된 변수의 타입 출력
System.out.println("b E Type : " + b.get().getClass().getName());
}
}
ClassName이란 객체를 생성할때 <>안에 타입 파라미터(type parameter)를 지정합니다.
a객체의 ClassName의 제너릭 타입은 String으로 모두 변환되고, b객체의 ClassName의 제너릭 타입은 Integer로 모두 변환됩니다.
결과)
a data : 10
a E Type : java.lang.String
b data : 10
b E Type : java.lang.Integer
예시- 값을 2개 사용할 때)
// 제네릭 클래스
class ClassName<K, V> {
private K first; // K 타입(제네릭)
private V second; // V 타입(제네릭)
void set(K first, V second) {
this.first = first;
this.second = second;
}
K getFirst() {
return first;
}
V getSecond() {
return second;
}
}
// 메인 클래스
class prac2 {
public static void main(String[] args) {
ClassName<String, Integer> a = new ClassName<String, Integer>();
a.set("10", 10);
System.out.println(" fisrt data : " + a.getFirst());
// 반환된 변수의 타입 출력
System.out.println(" K Type : " + a.getFirst().getClass().getName());
System.out.println(" second data : " + a.getSecond());
// 반환된 변수의 타입 출력
System.out.println(" V Type : " + a.getSecond().getClass().getName());
}
}
이렇게 외부 클래스에서 제네릭 클래스를 생성할때 <>안에 타입을 파라미터로 보내서 제네릭 타입을 지정해 줄 수 있습니다.
결과)
fisrt data : 10
K Type : java.lang.String
second data : 10
V Type : java.lang.Integer
3. 제네릭 메소드
클래스에서 이름 옆에 <T>등을 붙여 제네릭 타입을 설정하여 클래스 내에서 사용할 수 있었는데 클래스가 아닌 단일 메소드에만 한정된 제네릭도 사용할 수 있습니다.
제네릭 메소드는 제네릭 클래스에서 지정한 제네릭 유형과 다른 독립적인 제네릭 유형을 가질 수 있습니다.
기본적인 형식은 다음과 같습니다.
public <T> T genericMethod(T o) { // 제네릭 메소드
...
}
[접근 제어자] <제네릭타입> [반환타입] [메소드명]([제네릭타입] [파라미터]) {
// 텍스트
}
예시)
// 제네릭 클래스
class ClassName<E> {
private E element; // 제네릭 타입 변수
void set(E element) { // 제네릭 파라미터 메소드
this.element = element;
}
E get() { // 제네릭 타입 반환 메소드
return element;
}
<T> T genericMethod(T o) { // 제네릭 메소드
return o;
}
}
public class prac2 {
public static void main(String[] args) {
ClassName<String> a = new ClassName<String>();
ClassName<Integer> b = new ClassName<Integer>();
a.set("10");
b.set(10);
System.out.println("a data : " + a.get());
// 반환된 변수의 타입 출력
System.out.println("a E Type : " + a.get().getClass().getName());
System.out.println();
System.out.println("b data : " + b.get());
// 반환된 변수의 타입 출력
System.out.println("b E Type : " + b.get().getClass().getName());
System.out.println();
// 제네릭 메소드 Integer
System.out.println("<T> returnType : " + a.genericMethod(3).getClass().getName());
// 제네릭 메소드 String
System.out.println("<T> returnType : " + a.genericMethod("ABCD").getClass().getName());
// 제네릭 메소드 ClassName b
System.out.println("<T> returnType : " + a.genericMethod(b).getClass().getName());
}
}
예시)
a data : 10
a E Type : java.lang.String
b data : 10
b E Type : java.lang.Integer
<T> returnType : java.lang.Integer
<T> returnType : java.lang.String
<T> returnType : ClassName
제네릭 메소드의 파라미터 타입에 따라 T타입이 정해집니다.
'[WEB] > [Java]' 카테고리의 다른 글
[Java] 윈도우 자바 환경변수 설정방법 (0) | 2022.09.29 |
---|---|
[Java] 자바 컬렉션 2 (0) | 2022.09.25 |
[Java] 자바 컬렉션 (0) | 2022.09.24 |
[Java] Object 클래스 (0) | 2022.09.23 |
[Java] 인터페이스와 추상 클래스 (0) | 2022.09.23 |