IT 개발노트

제네릭스(Generics) 본문

기초튼튼/JAVA

제네릭스(Generics)

limsungju 2019. 2. 12. 13:44

1. 제네릭스(Generics)
1.1 제네릭스란?

: 제네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크(compile-time type check)를 해주는 기능이다.
객체의 타입을 컴파일 시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.
- 쉽게말해서 컬렉션 클래스가 다룰 객체를 미리 명시해줌으로써 형변환을 하지 않고 사용하는 것이다.

1.1.1 제네릭스의 장점
- 타입 안정성을 제공한다.
- 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.
: 다룰 객체의 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여준다.

1.2 제네릭 사용예시

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package Java.sungju.JavaProject;
 
import java.util.ArrayList;
 
public class JavaProject {
    public static void main(String[] args) {
        // <String> 제네릭스를 사용한 경우
        ArrayList<String> mStringList = new ArrayList<String>();
        mStringList.add("안녕하세요");
        mStringList.add("3");
        
        for(String s : mStringList) {
            System.out.println(s);
        }
        
        // <Integer> 제네릭스를 사용한 경우
        ArrayList<Integer> mIntegerList = new ArrayList<Integer>();
        mIntegerList.add(1);
        mIntegerList.add(2);
        
        for(Integer i : mIntegerList) {
            System.out.println(i);
        }
        
        // <Class명> 제네릭스를 사용한 경우
        ArrayList<Tv> mTvList = new ArrayList<Tv>(); {
            mTvList.add(new Tv());
            mTvList.add(new Tv("New Tv"));
            
            for(Tv t : mTvList) {
                System.out.println(t);
            }
            
            // < 제네릭스를 사용하지 않은 경우 >
            // 모든타입을 "add(Object)" Object형으로 List에 Add를
            // 시켜 주므로, List에서 자료를 꺼내올때는 각각에 맞는 형변환을
            // 꼭 해주어야 하기 때문에 번거 롭다.
            ArrayList mOriginalList = new ArrayList();
            mOriginalList.add(1);
            mOriginalList.add("string");
            mOriginalList.add(new Tv("original"));
            
            int a = (Integer) mOriginalList.get(0);
            String b = (String) mOriginalList.get(1);
            Tv c = (Tv) mOriginalList.get(2);
        }
    }
}
 
// Tv Class
class Tv {
    private String caption;
    
    public Tv() {
        this("Tv Class 입니다.");
    }
    
    public Tv(String caption) {
        this.caption = caption;
    }
    
    public String toString() {
        return caption;
    }
}


: 위의 예제처럼 상황에 맞는 <제네릭스>를 선택해서 사용하면 된다.
int대신 Integer를 사용한 이유는 <제네릭스>를 선언할 수 있는 타입이 객체 타입이기 때문이다.
int같은 경우에는 기본자료형이기 때문에 <제네릭스>타입 자료에는 들어갈수가 없다.
그래서 자료형을 객체화시킨 wrapper클래스를 사용해서 사용한다.
wrapper클래스란 기본형변수들에 기능을 좀더 추가해서 객체화 시킨 클래스이다.

1.3 제네릭의 다형성
: 다형성이란 '부모의 참조변수로 자식 객체를 참조할수 있는 것'이다.
예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package Java.sungju.JavaProject;
 
import java.util.ArrayList;
 
public class JavaProject {
    public static void main(String[] args) {
        
        // product클래스의 자손객체들을 저장할 수 있는 ArrayList를 생성
        ArrayList<Product> list = new ArrayList<Product>();
        list.add(new Product());
        list.add(new Vcr());
        list.add(new Audio());
        
        // 자손의 객체를 꺼내 올때는 형변환이 필요하다.
        Product p = list.get(0);
        Vcr v = (Vcr)list.get(1);
    }
}
 
class Product{};
class Vcr extends Product{};
class Audio extends Product{};


ArrayList가 Product타입의 객체를 저장하도록 지정하면, 이들의 자손인 Vcr과 Audio타입의 객체도 저장할 수 있다. 다만 꺼내올 때 원래의 타입으로 형변환 해야 한다.

1
2
3
// 자손의 객체를 꺼내 올때는 형변환이 필요하다.
Product p = list.get(0);
Vcr v = (Vcr)list.get(1);


하지만 매개변수 타입의 ArrayList<Product>로 선언된 경우, 이 메서드의 매개변수로 ArrayList<Product>타입의 객체만 사용할 수 있다. 그렇지 않으면 컴파일 에러가 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package Java.sungju.JavaProject;
 
import java.util.ArrayList;
 
public class JavaProject {
    public static void main(String[] args) {
        ArrayList<Product> pArrayList = new ArrayList<Product>();
        ArrayList<Vcr> vArrayList = new ArrayList<Vcr>();
        
        printAll(pArrayList);
        // 컴파일 에러
        printAll(vArrayList);
    }
    
    public static void printAll(ArrayList<Product> list) {
        for(Product p : list) {
            System.out.println(p);
        }
    }
}
 
class Product{};
class Vcr extends Product{};
class Audio extends Product{};


: 매겨변수의 다형성을 이용하기 위해서는 와일드 카드 '?'를 사용하면 된다.
보통 제네릭에서는 단 하나의 타입을 지정하지만 와일드 카드는 하나 이상의 타입을 지정하는것을 가능하게 해준다.

1.3.1 와일드카드 사용방법
: 만일 Product가 클래스가 아닌 인터페이스라 할지라도 키워드로 'implements'를 사용하지 않고 클래스와 동일하게 'extends'를 사용한다는 것에 주의하기

1
2
3
4
5
6
// Product 또는 그 자손들이 담긴 ArrayList를 매개변수로 받는 메서드
public static void printAll(ArrayList<extends Product> list) {
    for(Product p : list) {
        System.out.println(p);
    }
}


와일드 카드는 (ArrayList<? extends Product> list)말고도 또 다른 형식으로도 쓰인다.
바로 아래의 메서드 형식이다.

1
2
3
4
5
6
// 와일드 카드의 또다른 형식
public static <extends Product> void printAll(ArrayList<T> list) {
    for(Product p : list) {
        System.out.println(p);
    }
}


와일드 카드를 쓸때는 Product를 상속받은 클래스(Vcr, Audio)를 <제네릭>으로 사용하는 ArrayList를 생성한 후 메서드에 넣어 주면 된다.

<? extends T> : 와일드 카드의 상한 제한. T와 그 자손들만 가능
<? super T> : 와일드 카드의 하한 제한. T와 그 조상들만 가능
<?> : 제한 없음. 모든 타입이 가능. <? extends Object>와 동일

'기초튼튼 > JAVA' 카테고리의 다른 글

프로세스 호출 예제  (0) 2019.02.19
숫자맞추기 게임  (0) 2019.02.18
스레드  (0) 2019.02.10
JAVA 입출력(I/O) 알아보기  (0) 2019.02.10
컬렉션이란  (0) 2019.02.07