제네릭(Generic)Java2022. 12. 10. 14:11
Table of Contents
728x90
728x90
제네릭 Generic
타입을 파라미터화 하여 실행시에 구체적으로 해당하는 타입으로 결정
→ 특정(Specific)타입을 미리 지정해주는 것이 아닌 필요에 의해 지정할 수 있도록 하는 일반(Generic)타입
장점
- 잘못된 타입이 들어올 수 있는 것을 컴파일 단계에서 방지 가능
- 따로 타입을 체크하고 변환할 필요가 없다 (캐스팅 최소화로 인한 관리수월)
- 타입체크를 강력하게 하여 잘못된 데이터를 일반적인 원시, 참조 타입보다 안정성 확보에 좋음
- 코드의 재사용성이 높아짐
사용방법
타입 | 설명 |
<T> | Type |
<E> | Element |
<K> | Key |
<V> | Value |
<N> | Number |
- 반드시 한 글자일 필요도 없고 위의 표와 일치할 필요도 없다.
- Just 암묵적 규칙
선언
파라미터로 명시할 수 있는 것은 참조타입이다
- 사용자가 정의한 클래스도 타입으로 올 수 있다는 뜻과 같다
- int, double등 기본타입은 Integer, Double과 같은 Wrapper Type으로 사용한다
- static에는 제네릭 타입 선언 불가능하지만 정적 메서드에는 선언 가능 (밑에서 설명)
public class ExamMain<T> {
}
public Interface ExamMain2<T>{
}
// 멀티 제네릭
// 두 개 이상의 타입을 파라미터로 사용 가능
public class ExamMain<T, E> {
}
public Interface ExamMain2<K, V>{
}
제네릭 클래스
class ExamMain<E> {
private E element;
void set(E element) {
this.element = element;
}
E get() {
return element;
}
}
class genericExamMain {
public static void main(String[] args) {
ExamMain<String> a = new ExamMain<String>();
ExamMain<Integer> b = new ExamMain<Integer>();
a.set("안녕");
b.set(10);
System.out.println("a data : " + a.get());
System.out.println("a E Type : " + a.get().getClass().getName()); // 타입 출력
System.out.println("b data : " + b.get());
System.out.println("b E Type : " + b.get().getClass().getName()); // 타입 출력
}
}
// Console
a data : 안녕
a E Type : java.lang.String
b data : 10
b E Type : java.lang.Integer
// 멀티 제네릭
public class Tv<E, T> {
private E e;
private T t;
public Tv() {
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public E getE() {
return e;
}
public void setE(E e) {
this.e=e;
}
}
public class TvMain {
public static void main(String[] args) {
Tv<Integer, String> tv1 = new Tv<Integer, String>();
Tv<String, Float> tv3= new Tv<String, Float>();
tv1.setE(123456);
tv1.setT("가나다라마바");
tv3.setE("어쩔티비");
tv3.setT(12.345f);
int tv2=tv1.getE();
String tv4=tv3.getE();
System.out.println(tv2);
System.out.println(tv4);
}
}
// Console
123456
어쩔티비
제네릭 메서드
클래스에서 지정한 제네릭 유형과 별개로 독립적으로 제네릭 유형을 선언하여 사용 가능
public <T> T genericMethod(T t) {
return t;
}
// 접근제어자 <제네릭타입> 반환타입 메소드명(제네릭타입 파라미터)
// 위의 TV예제에 제네릭 메서드인 genericMethod메서드를 추가
public class Tv<E, T> {
private E e;
private T t;
public Tv() {
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public E getE() {
return e;
}
public void setE(E e) {
this.e=e;
}
<N> N genericMethod(N n) { // 제네릭 메소드
return n;
}
}
public class TvMain {
public <T> T genericMethod(T t) {
return t;
}
public static void main(String[] args) {
Tv<Integer, String> tv1 = new Tv<Integer, String>();
Tv<String, Float> tv3= new Tv<String, Float>();
tv1.setE(123456);
tv1.setT("가나다라마바");
tv3.setE("어쩔티비");
tv3.setT(12.345f);
int tv2=tv1.getE();
String tv4=tv3.getE();
System.out.println(tv2);
System.out.println(tv4);
System.out.println("<N> returnType : " + tv1.genericMethod(3).getClass().getName());
System.out.println("<N> returnType : " + tv1.genericMethod("ABCD").getClass().getName());
System.out.println("<N> returnType : " + tv1.genericMethod(tv3).getClass().getName());
}
}
// Console
123456
어쩔티비
<N> returnType : java.lang.Integer
<N> returnType : java.lang.String
<N> returnType : generic1201.Tv
메서드는 해당 클래스의 객체가 인스턴스화 됐을 때 <> 괄호 사이에 파라미터로 넘겨준 타입으로 지정이 된다
※ Static은 객체가 생성되기 이전, 즉 클래스가 생성될 때 같이 선언이 되기 때문에 제네릭 타입을 사용 불가능
(제네릭 타입을 얻어올 방법이 없다)
정적메서드를 두고 싶은 경우 제네릭 클래스와 별도로 독립적인 제네릭이 사용되어야 한다
제한된 Generic과 와일드카드
<E>를 외부클래스에서 String파라미터로 보내면 E는 String이되고, Integer을 보내면 E는 Integer이 된다
Tv<E>클래스를 만들고 파라미터를 TV로 보내면 E는 TV 클래스가 된다. → 참조타입이 될 수 있다
extends, super, ? 을 통해특정 범위로 좁혀서 제한할 수 있다 (여기서 ?는 와일드카드. 즉 알 수 없는 타입이라는 의미)
- extends T : 상한경계
- ? super T : 하한경계
- <?> : 와일드카드
<E extends T> // T와 T의 자손 타입만 가능 (E는 들어오는 타입으로 지정 됨)
<E super T> // T와 T의 부모(조상) 타입만 가능 (E는 들어오는 타입으로 지정 됨)
<? extends T> // T와 T의 자손 타입만 가능
<? super T> // T와 T의 부모(조상) 타입만 가능
<?> // 모든 타입 가능. <? extends Object>
위 그림과 같은 경우
<T extends B> // T = B~C
<T extends E> // T = E
<T extends A> // T = A~E
<? extends B> // ? = B~C
<? extends E> // ? = E
<? extends A> // ? = A~E
<T super B> // T = A~B
<T super E> // T = A,D,E
<T super A> // T = A
<? super B> // ? = A~B
<? super E> // ? = A,D,E
<? super A> // ? = A
<?> // 모든 타입 가능. <? extends Object>
public class Exam extends Object{
System.out.println("<?>(wild Card)와 같은 의미");
}
// 어떤 클래스를 만들던 extends Object를 암시적으로 상속받는다
728x90
300x250
@mag1c :: 꾸준히 재밌게
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!