Language/Java

JAVA 라이브러리 - 제네릭 클래스

simDev1234 2022. 8. 10. 20:18

|  제네릭이란?

[사전] Generic = 일반적이다
[정의] 하나의 코드로 여러 타입을 동시에 처리하는 기술

1.  타입 변수 표기법

- 제네릭에 지정하는 타입 변수 이름은 지정하는 사람의 마음이지만,

  적어도 그 타입 이름을 사용하는 클래스 또는 인터페이스 내에서는 통일성있게 사용하게 한다.

- 일반적으로 변수명과의 구분을 위해 한 개의 대문자로 표시하는 것이 관례이다.

- 타입 매개 변수는 기초 자료형으로 객체화될 수 없다.

 

T Type
E Element(요소)
N Number
K Key
V Value
S,U,V.....  

 

2. 제네릭 클래스

- 최상위 클래스 Object를 사용하면 어떤 타입의 인스턴스건 참조할 수 있다. (업캐스팅, 다형성)

- 이러한 원리를 이용해서 클래스를 작성할때 데이터 타입을 Object로 하면 여러 타입의 데이터를 담을 수 있게 된다.

public class Box {
    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

}

- 다만, 이럴 경우, 아래와 같이 객체 안의 데이터를 가져올 때 형변환이 불가피하게 된다.

import LibraryPractice.MyClass.Box;

public class GenericTest {
    public static void main(String[] args) {
        Box box = new Box();
        box.setData(123);
        int x = (Integer)box.getData(); //cast(형변환)필요
    }
}

- 이럴 때 제네릭을 사용하여 미리 타입을 지정한다면 사용시의 형변환의 번거러움을 줄일 수 있게 된다.

public class Box<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

}
import LibraryPractice.MyClass.Box;

public class GenericTest {
    public static void main(String[] args) {
        Box<Integer> box = new Box<>();
        box.setData(123);
        int x2 = box.getData(); // 형변환 필요 없음
    }
}

- 만약에 여러 개의 맴버변수에 서로다른 제네릭을 지정해야하는 경우(ex. key와 value가 타입이 다른 경우), 아래와 같이 작성할 수 있다.

public class Box3<K, V> {
    private K key;
    private V value;

    public void setData(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey(V key) {
        return this.key;
    }

    public V getValue(K key) {
        return this.value;
    }

}

 

3. 제네릭 메소드

- 제네릭 메소드의 경우 아래와 같이 반환타입 앞에 <E> 와 같은 형식으로 작성을 해준다.

public class Basket<T> {

    T data;

    public Basket(T data){
        this.data = data;
    }

    // 외부 배열 print
    public <E> void print(E[] arr){
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }

}

- 만약에 타입 변수를 특정 타입(예를 들어 String)으로 제한하고 싶은 경우, 아래와 같이 사용할 수 있다.

public <E extends String> 반환타입 method(E item){
	/* 생략 */
}

 

[ 제네릭 메소드로 만든 코드 ]

import java.util.ArrayList;
import java.util.Arrays;

public class Basket2<T> {
    private ArrayList<T> basket;

    public Basket2(T[] arr) {
        this.basket = new ArrayList<T>(Arrays.asList(arr));
    }

    public <E extends String> void printWithOwner(E str) { // E를 String으로 제한
        if (str.length() == 0) {
            System.out.println("please type Owner Name");
            return;
        }

        StringBuffer sb = new StringBuffer();
        sb.append(str + " : ");
        for (int i = 0; i < basket.size(); i++) {
            if (i != basket.size() - 1) {
                sb.append(basket.get(i) + ", ");
            }else{
                sb.append(basket.get(i));
            }
        }
        System.out.println(sb);
    }

}
import LibraryPractice.MyClass.Basket2;

public class GenericTest2 {
    public static void main(String[] args) {

        String owner = "sir.Tim Berners-Lee";
        String[] fruit = {"apple", "orange", "dragon fruit"};

        Basket2<String> basket = new Basket2<>(fruit);
        basket.printWithOwner(owner);

    }
}

>> 결과

sir.Tim Berners-Lee : apple, orange, dragon fruit