2017년 6월 13일 화요일

제네릭스( Generics )

Generics ?
제네릭스, 에너테이션, 열거형

제네릭스는 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입체크(compile-time type check)를 해주는 기능이다. 객체의 타입을 컴파일시에 체크하기 때문에 객체의 타입 안정성을 높이고 형변환의 번거로움이 줄어든다.

■ 제네릭스의 장점
1. 타입 안정성을 제공한다.
2. 타입체크와 형변환을 생략할 수 있으므로 코드가 간결해 진다.

 - 간단히 말하면 다룰 객체의 타입을 미리 명시해줌으로써 번거로운 형변환을 줄여준다는 이야기다

◇ 제네릭 클래스의 선언
제네릭 타입은 클래스와 메서드에 선언할 수 있다.  [ 제네릭 클래스 ]
45 lines (35 sloc)  1.45 KB
package common.fundament.generics;
/*
class Box {
Object item;
void setItem(Object item){this.item=item;}
Object getItem(){return item;}
}
* 위의 클래스를 제네릭 클래스로 변경하면 아래와 같이 클래스 옆에 '<T>'를 붙이면 된다.
* 그리고 'Object' 를 모두 'T'로 바꾼다.
* */
class Box<T>{ // 제네릭 타입 T를 선언
T item; // T를 '타입변수(Type variable)' 라고 하며, 'Type'의 첫 글자에서 따온것이다.
void setItem(T item){
this.item=item;
}
T getItem(){ return item;}
}
// T는 임의의 참조형 타입을 의미한다.
// 제네릭 클래스가 된 Box클래스의 객체를 생성할 때는 다음과 같이 참조변수와 생성자에 타입 T대신에
// 사용될 실제 타입을 지정해주어야 한다.
// Box<String> b = new Box<String>(); //타입 T 대신, 실제 타입을 지정
// b.setItem(new Object()); //에러. String 이외의 타입은 지정불가
// b.setItem("ABC"); //OK. String 타입이므로 가능
// String item = (String) b.getItem();//형변환 필요없음
// 위의 코드에서 타입 T 대신에 String타입을 지정해 주었으므로, 제네릭 클래스 Box<T>는 다음과 같이
// 정의된 것과 같다
class Box2<String> { // 제네릭 타입을 String으로 지정
String item;
void setItem(String item){
this.item=item;
}
String getItem(){
return item;
}
}

만일 Box클래스에 String만 담을거라면, 타입 변수를 선언하지 않고 위와 같이 직접 타입을 적어주는 것도 가능하다. 단, Box<String> 클래스는 String타입만 담을 수 있다. 반면에 Box<T>클래스는 어떤 타입이든 한 가지 타입을 정해서 담을 수 있다.

제네릭이 도입되기 이전의 코드와 호환을 위해, 제네릭 클래스인데도 예전의 방식으로 객체를 생성하는 것이 허용된다. 다만 제네릭 타입을 지정하지 않아서 안전하지 않다는 경고가 발생한다.

Box b = new Box();            // OK. T는 Objcet로 간주된다.
b.setItem("ABC");              // 경고, unchecked of unsafe operation
b.setItem(new Object());   // 경고, unchecked of unsafe operation


■ 제네릭스의 용어
 class Box<T> { }
Box<T>  제네릭 클래스, 'T의 Box' 또는 'T Box' 라고 읽는다.
T           타입변수, 또는 타입 매개변수. (T는 타입 문자)
Box        원시 타입 ( raw type )

타입문자 T는 제네릭 클래스 Box<T>의 타입변수 또는 타입 매개변수라고 하는데, 메서드의 매개변수와 유사한 면이 있기 때문이다. 

             대입된 타입(매개변수화된 타입, parameterized type)
Box<String> b = new Box<String>();
제네릭 타입 호출

위와 같이 타입 매개변수에 타입을 지정하는 것을 '제네릭 타입 호출' 이라고 하고, 지정된 타입 'String'을 '매개변수화 된 타입(parameterized type)' 이라고 한다. ( 대입된 타입 )
예를 들어, Box<String> 과 Box<Integer>는 제네릭 클래스 Box<T>에 서로 다른 타입을 대입하여 호출한것, 이 둘이 별개의 클래스를 의미하는 것은 아니다.

■ 제네릭스의 제한
 모든 객체에 대해 동일하게 동작해야 하는 static 멤버에 타입 변수 T를 사용 할 수 없다.
T는 인스턴스 변수로 간주되기 때문이다.
 static멤버는 인스턴스 변수를 참조할 수 없다.

class Box<T>{
      static T item; //에러
      static int compare(T t1, T t2){ } // 에러

static멤버는 타입 변수에 지정된 타입, 즉 대입된 타입의 종류에 관계없이 동일한 것이어야 하기 때문이다. 즉, 'Box<Apple>.item'과 'Box<Grape>.item'이 다른 것이어서는 안된다는 뜻이다.

 제네릭 타입의 배열을 생성하는것도 허용되지 않는다.
제네릭 배열 타입의 참조변수를 선언하는 것은 가능하지만, 'new T[10]' 과 같이 배열을 생성하는 것은 안된다는 뜻이다.
class Box<T>{
    T[] itemArr; //OK, T타입의 배열을 위한 참조변수
    T[] toArray() {
              T[] tmpArr = new T[itemArr.length];   // 에러, 제네릭 배열 생성불가
              return tmpArr;

제네릭 배열을 생성할 수 없는 것은 new 연산자 때문인데, 이 연산자는 컴파일 시점에 타입 T가 뭔지 정확히 알아야 한다. Box<T> 클래스를 컴파일 하는 시점에서는 T가 어떤 타입이 될지 전혀 알 수 없다.

댓글 없음:

댓글 쓰기

JavaScript_함수의 역할

◎ 자바스크립트 함수의 역할 ■ 자바스크립트 함수와 메서드는 전혀 다른 개념이다. - 자바스크립트 함수는 메서드 역할을 할 수 있지만, 객체지향 프로그래밍의 메서드는 자바스크립트의 함수 역할을 할 수 없다. - 메서드와는 다르게 ...