'unchecked'에 해당되는 글 1건

Java Generic Types

Java 2013. 11. 22. 12:39

참조 : http://docs.oracle.com/javase/tutorial/java/generics/types.html

Generic 을 쓰지 않는 간단한 클래스


Colored By Color Scripter

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


위의 Box 클래스는 non-generic 클래스이다. 이 클래스는 object를 받아들이고 리턴하므로 원하는 모든 타입을 세팅 할 수 있다 하지만 위와 같이 하면 컴파일시에 클래스가 어떻게 사용되는지에 대한 검증을 할 수 없다. Box를 사용하는 클라이언트가 set 메소드에 Integer를 사용하고 get 메소드에서 String으로 사용한다면 런타임시에 오류를 발생하게 된다.

Generic Type을 사용하도록 변경



generic class 는 다음 포맷으로 정의된다.

 Colored By Color Scripter

1
2
3
class name<T1,T2,...,Tn> {
    /* ... */
}


위의 Box 클래스를 generic type으로 변경하기 위해 코드를 다음과 같이 변경하다. 다음에 소개된 type variable 'T' 는 클래스 내부의 어느곳에서든 사용가능하다.

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


type variable 은 모든 클래스, 인터페이스, array 타입 등 어느 타입이라도 될수 있다. 해당 기술 기반으로 generic interface를 만드는 것도 가능하다.


Type Parameter Naming Conventions



가장 많이 사용되는 type paramenter names

  • E - element (Java Collection 에서 가장많이 사용)
  • K - key
  • N - Number
  • T - type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types


Generic Type 호출(Invoking)과 인스턴스화(Instantiating)



예제의 generic Box 클래스를 참조하기 위해서는 다음과 같이 변수를 선언한다. T를 Integer 와 같은 concrete value로 대체해야 한다.

1
Box<Integer> integerBox;


You can think of a generic type invocation as being similar to an ordinary method invocation, but instead of passing an argument to a method, you are passing a type argument.

[직역 : method invocation과 유사하다고 생각할수 있지만 메소드는 인수를 전달하는 대신 generic은 type 인수를 전달한다.]

* Type Parameter 오 Type Argument 용어 : 대부분 개발자는 type parameter와 type argument를 혼용해서 사용하지만 이 용어들은 똑같은 의미가 아니다. 코딩시에 parameterized type을 생성하기 위해 type arguments를 제공한다. 그러므로 Foo<T> 에서의 T는 type parameter이고 Foo<String> 의 String은 type argument이다. 

다른 변수 선언과 마찬가지로 위의 코드는 실제로 Box를 생성하지 않는다. 단순히 변수를 선언한 것이다. generic type 호출(invocation)은 일반적으로 parameterized type으로 알려저 있다. 이 클래스를 인스턴스와 하기 위해 new를 사용해야 한다.

 Colored By Color Scripter

1
Box<Integer> integerBox = new Box<Integer>();

The Diamond



Java SE 7 이후 부터 비어있는 type arguments를 지원한다. 

1
Box<Integer> integerBox = new Box<>();

<>는 일반적으로 Diamond라고 불린다.


Multiple Type Parameters




전에 언급했듯이 generic 클래스는 여러개의 type paramter들을 가질 수 있다. 예를 들어 Pair인터페이스를 구현하는 OrderPair generic 클래스는 다음과 같다.

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 generic;
 
public class OrderPair<K, V> implements Pair<K, V> {
 
    private K key;
    private V value;
 
    public OrderPair(K key, V value) {
        this.key = key;
        this.value = value;
    }
 
    @Override
    public K getKey() {
        return this.key;
    }
 
    @Override
    public V getValue() {
        return this.value;
    }
 
}
 

다음 코드는 OrderPair 클래스를 생성하는 코드이다.

1
2
Pair<String, Integer> p1 = new OrderPair<String, Integer>("Evne", 8);
Pair<StringString> p2 = new OrderPair<StringString>("hello""World");


Parameterized Types




type parameter를 parameterized type 으로 대체 할 수 있다 .다음과 같이 사용이 가능하다.

1
2
3
4
5
6
GenericBox<Integer> genericBox = new GenericBox<Integer>();
genericBox.set(3);
Pair<String, GenericBox<Integer>> p = 
      new OrderPair<String, GenericBox<Integer>>("primes", genericBox);
p.getKey(); // primes
p.getValue(); // 3


Row Types




row type은 type argument들이 없는 제네릭 클래스 혹은 제네렉 인터페이스의 이름이다. 위의 Box 클래스를 생성할때 다음과 같이 타입이 없이 생성 할 수 있다. Box rowBox = new Box(); 이때 Box는 generic type Box<T> 의 row type이다. 그러나 non-generic 클래스 혹은 인터페이스타입은 raw 타입이 아니다.

Raw 타입들은  legacy 코드에서 많이 보여진다. 왜냐하면 수많은 API 클래스들(Collection 클스들과 같음)은 JDK 5.0 이전에는 generic 타입이 아니었기 때문이다. row 타입들을 사용할 때, Box 클래스의 get메소드는  object를 리턴할 것이다. 하위버전과의 일치성을 위해 parameterized type을 row type으로 할당하는 것은 허용된다.

1
2
Box<String> stringBox = new Box<>();
Box rowBox = stringBox; // OK


그러나 row type을 parameterized type으로 할당하는 것은 warning 이다.

1
2
Box rowBox = new Box(); // rowBox is a raw type of Box<T>
Box<Integer> intBox = rawBox;  // warning : unchecked conversion


다음과 같이 row 타입에서 generic type 으로 정의되어 있는 generic 메소드를 호출하는 것 또한 warning이다.

1
2
3
Box<String> stringBox = new Box<>();
Box rowBox = stringBox; // OK
rowBox.set(8) // warning : unchecked invocation to set(T)


row 타입사용은 안전하지 않기 때문에 사용을 피해야 한다.


Unchecked Error Messages



언급했듯이 legacy 코드와 generic 코드가 섞여 있들때 다음과 같은 경고 메세지를 볼 수있다. 

Note : Example.java uses unchecked or unsafe operations.

Note : Recompile with -Xlint:unchecked for details.

다음과 같은 코드가 있을때 위의 에러가 발생한다.

1
2
3
4
5
6
7
8
9
10
public class WarningDemo {
    public static void main(String[] args){
        Box<Integer> bi;
        bi = createBox();
    }
 
    static Box createBox(){
        return new Box();
    }
}

unckecked 의 의미는 컴파일러가 type safety의 모장에 대한 모든 타입 체크에 대해 충분한 타입 정보를 가지고 있지 않다는 것이다. "unchecked" 경고는 기본으로 비활성화 되어 있다. 모든 "unchecked"에 대한 경고를 보기 위해서 컴파일시에 다음과 같은 옵션을 준다. "-Xlint:unchecked".

위의 클래스에 Xlint:unchecked 옵션을 주고 컴파일을 하면 다음과 같은 경고 메세지를 볼 수 있다.

WarningDemo.java:4: warining : [unchecked] unchecked conversion

found : Box

required: Box<java.lang.Integer>

bi = createBox();

1 warning; 




블로그 이미지

비추마

,