2010-01-11 8 views
2

Java Generics : javac 또는 Eclipse 컴파일이 누구입니까?

이 메소드를 호출하는 방법은 다음과 같습니다.

public static @Nonnull <TV, TG extends TV> Maybe<TV> something(final @Nonnull TG value) { 
    return new Maybe<TV>(value); 
} 

public @Nonnull Maybe<Foo> visit() { 
    return Maybe.something(new BarExtendsFoo()); 
} 
Eclipse에서 올바르게 컴파일되지만 javac은 "호환되지 않는 유형"경고를 표시합니다.

found : BarExtendsFoo 

필수 : ​​Foo

+2

동작하는 예제와 클래스를 누락 쉽게 사람들이 도움을 할 수 있도록합니다 : 그것은 당신이 메소드를 호출 할 방법을 컴파일러와 인간의 독자 모두에게 지금은 명확합니다. –

+0

간단한 질문이 있습니다 ... 컴파일러는 호출 할 때 반환 할 실제 유형을 어떻게 알 수 있습니까 : 'Maybe.something (new BarExtendsFoo())'? –

+0

왜 public @Nonnull 어쩌면 visit() {...} ? –

답변

2

javac에서 C를 유추하지 않은 이유를 모르겠습니다. orrect 유형,
하지만 수 도움

public @Nonnull Maybe<Foo> visit() { 
    return Maybe.<Foo, BarExtendsFoo>something(new BarExtendsFoo()); 
} 
+1

something() 메서드의 다소 복잡한 서명으로이 명시적인 입력을 피하기 위해 실제로이 문제가 수정되었습니다. 어쨌든 유형을 제공하기 위해 필요로하는 지금이 그것을 단순화 : 어쩌면 일 (최종 TV 값) 모든 힌트를 감사합니다. – tbk

5

에서와 유형을 공급하여 컴파일러 javac의 이클립스 사이에 약간의 차이가 분명히있다. 그러나 여기서 요점은 javac이 오류를 방출하는 것이 맞다는 것입니다. 궁극적으로 코드가 어쩌면 <BarExtendsFoo>을 <Foo>으로 변환하는 것이 위험합니다. 여기

는 방문() 메소드의 재 작성의 :

public static <TV, TG extends TV> Maybe<TV> something(final TG value) { 
    return new Maybe<TV>(value); 
    } 

    public static class Foo { } 

    public static class BarExtendsFoo extends Foo { } 

    public Maybe<Foo> visit() { 
    Maybe<BarExtendsFoo> maybeBar = something(new BarExtendsFoo()); 
    Maybe<Foo> maybeFoo = maybeBar; // <-- Compiler error here 

    return maybeFoo;  
    } 

이 재 작성 코드에 실질적으로 동일하지만, 명시 적으로 푸 아마 <에 BarExtendsFoo > 어쩌면 <에서 만들려고 노력하고있는 할당을 보여줍니다 >. 이것은 위험합니다. 실제로 제 이클립스 컴파일러는 할당 라인에서 오류를 발생시킵니다.

public static void bomb() { 
    Maybe<String> maybeString = new Maybe<String>(""); 

    // Use casts to make the compiler OK the assignment 
    Maybe<Object> maybeObject = (Maybe<Object>) ((Object) maybeString); 
    maybeObject.set(new Integer(5)); 

    String s = maybeString.get(); // Runtime error (classCastException): 
            // java.lang.Integer incompatible with 
            // java.lang.String 
    } 
+0

어쩌면 에서 아마도 으로의 변환은 내가 기대하는 바가 아닙니다. something() 메서드는'아마도 '을 반환해야하므로'TV'는 BarExtendsFoo가 아닌 Foo가됩니다. 다시 쓰기는 javac에 대해서만 유효합니다 (동일). 이클립스 솔기는 예상 된 반환 값을 사용하여 (올바른?) 'TV'유형을 추측하여 something()이 을 생성 할 수 있도록합니다. –

0

두 의견 :

을 여기에 아마 < 문자열 > 객체 내부에 정수를 저장하기 위해 이러한 위험을 악용하는 코드 조각입니다. 여러분의 의견 중 하나에서 언급했듯이, 메소드에서 수행중인 TG 하위 클래스에 특정한 것이 없으므로 something()의 시그니처는 전혀 필요하지 않습니다.

b. 이것에 대한 가장 쉬운 해결책은 새로 생성 된 객체를 변수에 명시 적으로 할당하여 컴파일러가 어떤 유형을 사용하는지 이해하는 것입니다 (일반적으로 좋은 연습입니다). 표준이 아닌 주석없이

public @Nonnull Maybe<Foo> visit() { 
    final Foo bar = new BarExtendsFoo(); 
    return Maybe.something(bar); 
}