컴퓨터공부/Kotlin & Java

Java Generic, 자바 제네릭

achivenKakao 2020. 9. 30. 03:29

더 자세한 것은 출처를 참고 하시면 됩니다.

아래는 제가 이해하기에 도움 되는 수준으로 정리 한 것입니다.

 

제네릭 클래스

public class 클래스<T> { ... }

// 가장 기본적인 형태의 제네릭 클래스
class GenericClass<T>{
    private T t;

    T getValue(){           // 제네릭 class 내 에서는 제네릭 타입에 대한 리턴 정의가 편하다.
        return t;
    }
}

// Generic class를 상속 받으면 제네릭 타입도 같이 받아야 한다.
class extendedClass<T> extends GenericClass<T>{

}

// Generic class를 상속받고, 제네릭 타입 K 도 받는 형태
class extendedClass2<T, K> extends GenericClass<T>{
    private K k;
}

interface Entry<K, V>{
    V getKey(K k);
    void setKey(V v);
}

class implementedClass<K, V> implements Entry<K, V>{
    @Override
    public V getKey(K k) {
        return null;
    }

    @Override
    public void setKey(V v) {

    }
}

// 제레릭 클래스를 리턴하는 함수
public <T> GenericClass<T> getGenericClass(T t){
    GenericClass<T> ret = new GenericClass<>();

    return ret;
}

 

제네릭 함수

타입파라미터가 앞에 나오기에 모르면 읽을 수 조차 없다.

public <타입파라미터> 리턴타입 메소드명(매개변수, ...) { ... }

public int original_Object(Object object){

    int castedT = (Integer)object;       // Object 사용시 type cast는 피할수 없다. 

    return castedT;
}

public <T> int Generic_Original_func(T t){
    // type cast 없이 사용 가능
    return 0;
}

// 파라미터 타입을 제한한 형태
public int func1(List<? extends Number> list){

    return 0;
}

// 제네릭 타입을 리턴 하고 싶은데, 타입이 안 맞을 경우
public <T> T func2(String a, Integer b){

    // 제네릭 타입 T와 리턴이 일치 하지 않으면 컴파일 에러가 발생한다.
    // 이럴 경우 type cast가 필요하다.
    return (T) (a + String.valueOf(b));

}

// 멀티 타입 파리미터 제네릭,
// + 파라미터 타입을 제한한 형태
// + 제네릭 타입 리턴
public <T, V> V func3(List<? extends V> list, T t, V v){

    if(list != null)
        return list.get(0);  // list의 타입이 V로 확실 하기에 컴파일 에러가 발생하지 않는다.

    // v의 타입이 확실히 V이기에 컴파일 에러가 발생하지 않는다.
    return v;               
}

// 제레릭 클래스를 리턴하는 함수
public <T> GenericClass<T> getGenericClass(T t){
    GenericClass<T> ret = new GenericClass<>();

    return ret;
}

 

와일드 카드

와일드 카드라고 표현하고 제한자라고 이해하면 적당하다.

 

아래는 재귀 호출을 하는 함수이다.

funcWild의 첫번째 파라미터를 Number의 파생된 파라미터만 받기 때문에, integerArrayList는 정상적으로 동작하지만,

stringArrayList를 컴파일 에러를 낸다.

    public <V> int funcWild(List<? extends Number> list, V v){

        ArrayList<Integer> integerArrayList = new ArrayList<>();
        funcWild(integerArrayList, 3);

        ArrayList<String> stringAarrayList = new ArrayList<>();
        funcWild(stringAarrayList, 3);           // compile error 발생

        return 0;
    }

하지만 아래 코드는 아무 문제 없이 돌아간다. 즉 와일드 카드는 제한자로 이해하면 된다. 

조금 더 응용하면 public <V> int funcGeneric_NoWild(List<?> list, V v) 도 쓰일 수 있다.

//    public <V> int funcGeneric_NoWild(List<?> list, V v){     // 이렇게 해도 문제가 없다.
    public <V, K> int funcGeneric_NoWild(List<K> list, V v){

        ArrayList<Integer> integerArrayList = new ArrayList<>();
        funcGeneric_NoWild(integerArrayList, 3);

        ArrayList<String> stringAarrayList = new ArrayList<>();
        funcGeneric_NoWild(stringAarrayList, 3);

        return 0;
    }

 

와일드카드는 파라미터, 필드, 지역 변수의 타입 또는 때때로 반환 타입과 같은 다양한 상황에서 사용될 수 있습니다. 와일드 카드는 제네릭 메소드 호출에 대한 형식 인수, 제네릭 클래스 인스턴스 생성, 또는 슈퍼타입으로 사용될 수 없습니다.


제네릭타입<?> : 타입 파라미터를 대치하는 것으로 모든 클래스나 인터페이스타입이 올 수 있습니다.

제네릭타입<? extends 상위타입> : 와일드카드의 범위를 특정 객체의 하위 클래스만 올 수 있습니다.

제네릭타입<? super 하위타입> : 와일드카드의 범위를 특정 객체의 상위 클래스만 올 수 있습니다.

 

출처 : 나

cornswrold.tistory.com/180

madplay.github.io/post/java-generic-advanced

tcpschool.com/java/java_generic_various

https://offbyone.tistory.com/327

ict-nroo.tistory.com/42

 

eskeptor.tistory.com/84

movefast.tistory.com/74

stackoverflow.com/questions/450807/how-do-i-make-the-method-return-type-generic

stackoverflow.com/questions/23349329/java-generic-return-type

coding-factory.tistory.com/573