Tag: generic

Java generic in return context

Posted by – 2009-09-25

아래 코드를 보시고 1, 2번 라인중에 어디서 에러가 날 지를 찾아보세요.

interface B {
  void doB();
}
class D implements B {
  public void doB() {}
}
interface H {
  B getB();
}
class HImpl implements H {
  public B getB() {
    return new D();  // 1)
  }
}
...
H h = new HImpl();
D d = h.getB(); // 2)

네, 2번 라인입니다.

그럼 다음 코드는?

interface B1 {
  void doB1();
}
interface B2 {
  void doB2();
}
class D implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
interface H {
  <T extends B1 & B2> T getB();
}
class HImpl implements H {
  public <T extends B1 & B2> T getB() {
    return new D();  // 1)
  }
}
...
H h = new HImpl();
D d = h.getB(); // 2)

네, 1번입니다. 잘 이해가 되질 않아 사내 메일링 리스트에 물어보니

I think you're seeing and interpreting it as "this method can return anything that implements both interfaces". What it's actually saying is "the caller is going to tell you a specific class that implements both interfaces, and you must return one of those".

이랍니다. 즉 T 타입이 아직 결정되지 않은 상태라 D와 T는 compatible한 타입이 아닌거죠.

강제로 casting을 해서 컴파일이 되게 만들면 그 코드는 runtime error (ClassCastException)를 발생하게 됩니다. 다음 코드를 보세요. 즉 이런 방법으론 도저히 type-safe한 코드를 작성할 수 없습니다.

class D2 implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
...
D2 d = h.getB(); // ClassCastException!!

이 같은 상황을 방지하기 위해 1번 라인에서 에러를 내 주는 것이죠.

코딩 가이드라인을 만들어 보자면 "method의 parameter로 사용되지 않는 type variable을 사용하면 안된다"입니다. 다음과 같은 경우는 parameter로도 사용되고 있으므로 문제가  없는 경우들입니다.

<T> T makeInstance(Class<T> cls) { return cls.newInstance(); }
...
<T extends Comparable<? super T>> T min(T a, T b) {
 return a.compareTo(b) < 1 ? a : b;
}

위의 예제 코드같은 경우 아래와 같은 방법으로 type-safe하게 작성될 수 있습니다.

interface B1 {
  void doB1();
}
interface B2 {
  void doB2();
}
class D implements B1, B2 {
  public void doB1() {}
  public void doB2() {}
}
interface H  <T extends B1, B2> {
  T getB();
}
class HImpl implements H<D> {
  public D getB() {
    return new D();  // 1)
  }
}
...
H<D> h = new HImpl();
D d = h.getB(); // 2)

사실... 아직도 잘 모르겠어요. Java generic. =(