티스토리 뷰

제네릭(Generic)이란?

: 클래스나 메서드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법

 

● 장점

1. 클래스나 메소드 내부에서 사용되는 객체의 타입 안정성을 높일 수 있음

 

List<Integer> list = new ArrayList<>();

//이경우 타입 에러가 발생
list.add("abc");

//이경우 타입 에러가 발생하지 않음
list.add(1);

 

Integer라는 타입을 명시해줌으로써 다른 타입의 데이터가 들어가면 에러가 발생하여 미리 잘못된 데이터 타입을 거를 수 있게 된다.

 

 

 

2. 반환 값에 대한 타입 변환 및 타입 검사에 들어가는 노력을 줄일 수 있음

ArrayList list = new ArrayList(); //제네릭을 사용하지 않을경우

list.add("test");
String s = (String) list.get(0);

list.add(1);
int i = (int) list.get(1);

 

제네릭을 사용하지 않는 경우 데이터를 받을 때 형 변환을 통해야만 가능하다.

또한 String 타입이 맞는지 확인하고 데이터를 받을 때 타입 검사를 해야 한다는 번거로움이 있다.

 

 

사용법

설계 시 클래스와 메서드 타입에 사용될 수 있음

 

-클래스

class Example<T> {
	private T t;

    public void setT(T t) {
        this.t = t;
    }
			
    public T getT() {
        return t;
    }
    
}

 

사용 예시

Example<String> ex = new Example<>();
ex.setT("ex");

 

-인터페이스

interface Example<T> {
    T example();
}

class ExampleImple implements Example<String> {

    @Override
    public String example() {
        return "";
    }
}

 

 

못된 사용법

제네릭은 지정이 가능한 타입이면 다 정상적으로 작동을 해야 한다. 하지만 아래와 같은 경우 정상적이게 작동하지 않게 된다.

 

 

상황 ) 인터페이스를 구현하는 구현 클래스들이 각각 다른 타입으로 반환되는 경우

 

-인터페이스

interface Animal<T>{
	
    public T act();
}

 

 

-구현 클래스

class Tiger<T> implements Animal<T>{

	public T act(){
    	return (T) new A();
    }
}

 

class Bird<T> implements Animal<T>{

	public T act(){
    	return (T) new B();
    }
}

 

-사용

Tiger<A> tiger = new Tiger<>();
A a = tiger.act();

Bird<B> bird = new Bird<>();
B b = bird.act();

* 이렇게 설계하는 방법이 좋지 않음! 예시를 든 것!

 

 

 

사용하는 것에 문제는 없지만 제네릭 사용 의도에 맞지 않는다. 잠재적인 문제가 생기기 때문이다.

 

Tiger<T>에서 T 타입에 어떤 것이 들어가도 정상 동작이 되어야 하지만 이 경우 A타입이 아닌 다른 데이터 타입이 들어가면 에러가 발생하게 된다.

 

이경우 인터페이스 구조를 다시 생각하여 설계하거나 다른 방법을 취해주어야 한다. 아래 내용과 같이 타입을 한정시켜 사용하는 방법도 있다.

 

 

 

 

타입을 한정하기

 

-구현 클래스

class Tiger<T extends A> implements Animal<T>{

	public T act(){
    	return (T) new A();
    }
}

 

-사용

Tiger<B> tiger1 = new Bird<>();//에러가 발생
B b = tiger1.act();

Tiger<A> tiger2 = new Tiger<>();//정장 작동
A a = tiger2.act();


 

<T extends A> 이런 식으로 타입을 한정해주면 다른 타입이 들어갈 경우 런타임이 아닌 이전에 타입을 미리 체크할 수 있게 된다.

 

 

 

 

 

 

 

* 제네릭을 공부하면서 정리해본 내용이므로 더 공부해야 할 내용과 수정되는 내용이 있을 수 있음!

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함