반응형

1. 개요

Generic 프로그래밍, Generic 프로그래밍을 사용하는 이유를 예제를 통해 알아보자.


2. Generic 프로그래밍이란?

 제네릭 프로그래밍이란 하나의 데이터가 특정 데이터 타입에만 종속되지 않고 여러 데이터 타입을 가질 수 있는 기술에 중점을 두어 재사용성을 높일 수 있는 프로그램 방식이다. - 위키백과

 

 무슨 말인지 이해가 잘 안간다. 일단 Generic이 무슨 의미를 갖는지 확인해보자.

 

 Generic의 사전적 의미는 '포괄적인, 총칭, 일반적인' 이다.

 

 이를 Generic 프로그래밍의 정의와 혼합하여 생각해보니 '데이터를 포괄적으로 사용할수 있도록 하는 프로그래밍, 어떤 데이터 타입도 가질 수 있도록 일반화시키는 프로그래밍' 으로 이해를 해보았다.

 

 그렇다면 데이터를 포괄적으로 사용한다는 것이 프로그래밍에서 어떤 의미를 가질까?

 어떤 데이터가 A가 될수도, B가 될수도, C가 될수도 있다라고 생각이 되는데... 예제를 통해 이해해보자.


3. 예제

Box.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Box<T> {
 
    private T t;
    
    public void set(T t) {
        this.t = t;
    }
    
    public T get() {
        return t;
    }
}
cs

이 Box 클래스는 제네릭한 클래스이다. T란 녀석이 중간 중간 껴있는 것을 확인할 수 있는데,

T는 내가 생성한 클래스도, 타입도 아니다. Generic 한 클래스를 만들기 위해 사용하는 제네릭 변수이다.

 

Box 객체 생성시 제네릭 변수 T로 들어온 데이터 형을 아래와 같이 변환(?) 시켜준다.

main 메서드의 예제를 보면 이해할 수 있을 것이다.

Generic Class

 

 

Main.java

1
2
3
4
5
6
7
8
9
10
11
public class Main {
 
    public static void main(String[] args) {
        Box<Integer> box = new Box<Integer>();
        box.set(10);
        
        Integer i = box.get();
        System.out.println(i.intValue());
    }
}
 
cs

다음과 같이 Box<Integer> box = new Box<Integer>() 로 생성하면, 앞서 이미지의 T 값이 Integer가 되는 것이다.

그럼 Box 클래스는 Integer 타입의 데이터를 관리할 수 있는 객체로 활용되게 된다.

 

Box<String> box = new Box<String>() 으로 생성하면 Box 클래스는 String 타입의 데이터를 관리하고, Human 으로 생성하면 Human 타입의 데이터를 관리하게 된다. 이제 Box라는 클래스가 특정 데이터 타입에 종속되지 않는 Generic한 클래스가 된 것이다.

 

그래도 이해가 잘 안된다면 ArrayList를 생각해봐도 좋을 것 같다.

ArrayList 생성 시 new ArrayList<String>, new ArrayList<Integer>, new ArrayList<Human> 형태로 작성하게 되는데, 입력한 데이터 타입에 따라 add할 수 있는 데이터 타입이 정해지게 된다. Generic과 비슷한 형태와 성질을 띄는 것 같지 않는가?

 

덧붙이면 예제에는 제네릭 변수를 T로 사용했는데 굳이 T가 아니어도 된다. K, V, A 등의 값으로 사용해도 된다.

 

Pair.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Pair<K,V> {
 
    private K key;
    private V value;
    
    public void set(K key, V value) {
        this.key = key;
        this.value = value;
    }
    
    public K getKey() {
        return key;
    }
    
    public V getValue() {
        return value;
    }
}
cs

Pair 클래스의 제네릭 변수를 K, V로 하여 클래스를 작성하였다.

그리고 main 메서드에서 K에는 String 타입을, V에는 Integer 타입으로 Pair 객체를 생성하였다.

 

1
2
3
4
5
6
7
8
9
10
public class Main {
 
    public static void main(String[] args) {
 
        Pair<String, Integer> pair = new Pair<String, Integer>();
        pair.set("test"9);
        System.out.println(pair.getKey()); // test
        System.out.println(pair.getValue()); // 9
    }
}
cs

 

그런데 생각해보니 Object로 대체해도 Generic한 클래스가 되지 않을까?

Box 클래스의 T를 빼버리고, Object 타입으로 넣으면 Object 타입은 모든 클래스의 슈퍼클래스이기 때문에 정형화시킬 수 있지 않는가? 그런데 왜 굳이 Object를 쓰지 않고 Generic을 사용할까?

 


4. Generic 사용 이유

Box.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Box {
 
    private Object t;
    
    public void set(Object t) {
        this.t = t;
    }
    
    public Object get() {
        return t;
    }
}
cs

제네릭 변수를 빼고 Object로 치환하였다.

 

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
 
    public static void main(String[] args) {
 
        Box box = new Box();
        box.set(10);
        
        //Integer i = box.get(); // 컴파일 에러
        Integer i = (Integer) box.get();
        System.out.println(i.intValue());
    }
}
cs

그리고 main 메서드에서 Box 객체를 생성하였더니 box.get() 부분에서 컴파일 에러가 발생하였다.

Integer i = box.get() 은 슈퍼클래스인 Object를 서브 클래스인 Integer가 참조하려는 형태이기 때문에 에러가 발생한다.

그래서 강제로 캐스팅하는 코드를 추가해주고 있다.

 

반면에 Generic 클래스를 사용하면 캐스팅하는 코드가 없다. Object를 사용하는 것보다 효율적이다.

 

추가적으로 Generic을 사용하면 컴파일 시점에 잡을 수 없었던 타입 에러를 검출 할 수 있다. 

 

Main.java

1
2
3
4
5
6
7
8
9
10
11
12
public class Main {
 
    public static void main(String[] args) {
 
        Box box = new Box();
        box.set(10);
        
        //Integer i = box.get(); // 컴파일 에러
        String i = (String) box.get();
        System.out.println(i);
    }
}
cs

다음과 같이 9행을 String으로 수정하였다.

box.get 이라는 메서드는 Object 형태의 데이터를 return 하기 때문에 컴파일 시점에서는 Integer로 받아도, String으로 받아도 상관없다. 그래서 컴파일 에러가 발생하지 않는다. 하지만 런타임 시 10이라는 정수 타입의 변수라 들어가게 되고, 9번 라인에서 Integer를 String 타입으로 변환하려 하니 castException이 발생하게 된다.

castException

Generic은 캐스팅 할 필요가 없기 때문에 이러한 문제가 발생하지도 않는다.

 

이처럼 Generic은 Object를 사용하는 방법보다 효율적임을 알 수 있다.

 


5. 마치며

오늘은 Generic에 대한 개념을 잡자는 목적으로 포스팅을 하였는데, 목적을 달성했다는 느낌이 든다.

기부니가좋다.

 

반응형

+ Recent posts