2017-04-10 1 views
0

나는 제네릭으로 약간의 손실이 있습니다. Java 컴파일러에서 제네릭 형식을 반환하지 않는 이유는 무엇입니까?

public interface SampleValue<T> { 
    T getValue(); 
} 

public static class SampleBoolean implements SampleValue<Boolean> { 
    @Override 
    public Boolean getValue() { 
     return Boolean.TRUE; 
    } 
} 

public static final class SampleValueGenerator { 
    private SampleValueGenerator() { 
     // do not call 
    } 

    public static <T, R extends SampleValue<T>> R forType(Class<T> clazz) { 
     if(Boolean.class.equals(clazz)) { 
      return new SampleBoolean(); 
     } 
    } 
} 

나는이 시도

, 인 IntelliJ (즉, 컴파일러가) RSampleBoolean합니다 ( return 라인) 호환되지 않는 유형은 내게 말한다 : 나는 다음과 같은 코드가 있습니다.

나는 제네릭이 아닌 (원시) 반환 형식을하려고하면

public static <T> SampleValue forType(Class<T> clazz) {

내가 어떤 오류가 발생하지 않는다; 합니다 (? 와일드 카드)

public static <T, R extends SampleValue<?>> R forType(Class<T> clazz) {

그러나 다시 실패. 그리고

public static <T> SampleValue<T> forType(Class<T> clazz) {

위해 나는 Incompatible types, Found: SampleBoolean, Required: SampleValue<T>를 얻을.

내 생각에 예를 들면 다음과 관련이 있습니다. 목록 (하지만 형제 자매)의 조상이 아닌 목록,하지만 위의 나무에 대한 나무를보고 실패.

누군가가 무슨 일이 일어나고 있는지, 그리고 긴 예제가 효과가없는 이유를 설명해 주실 수 있습니까?

업데이트 :주의 : 아이디어는 서로 다른 유형의 몇 경우/다른 지점을 가지고 있었으나 컴파일러가 불평을 시작했을 때 나는

+1

'AnotherAsSampleBoolean 클래스를 선언하여 샘플 값을 {...}'로 구현 한 다음'AnotherSampleBoolean result = forType (Boolean.class)'를 호출하면 예제 코드를 만들 수 있습니다. 'R'는'AnotherSampleBoolean'으로 추정 될 것이고 런타임에는'SampleBoolean'을'AnotherSampleBoolean'으로'ClassCastException'를 던질 것입니다. 그래서 예를 들면 다음과 같이하면됩니다. 컴파일러 오류를 피하기 위해 검사되지 않은 캐스팅을 사용하면 ' SampleValue forType (클래스 )'선언이 가장 안정적입니다. – Radiodef

+0

의미의 종류를 만드는 @Radiodef하지만' SampleValue forType (클래스 )'도 실패 ... – Christian

+0

'공공 정적 SampleValue forType (클래스 를 clazz) {'(와일드 카드, 제네릭이 아닌 반환 형식) works ... – Christian

답변

0

당신이 반환되는 R ... 정지 항상 구현하는 R입니다 Boolean의 SampleValue이며 T의 SampleValue (런타임에 설정되는 제네릭 형식)를 구현하는 R이 아닙니다. 이 일을해야

// if i do this 
SampleValueGenerator.forType(Integer.class) 
// i am expecting something that implements SampleValue<Integer> 
// but you are always returning something that implements SampleValue<Boolean> 

편집

public static <T, R extends SampleValue<T>> R forType(Class<T> clazz) { 
    return() -> { 
     try{ 
      return (T)clazz.newInstance(); // Also clazz should have a default constructor. 
     }catch(Excepetion e){ 
      // This catch block should be for NoSuchMethodException and InstantionException 
     } 
    } 
} 
1

나는 문제가 SampleBoolean가 특정 유형이 아닌 일반적인 뭔가 SampleValue<Boolean>을 구현한다는 생각 (아직 테스트하지 않았다). 한편, R은 제네릭 타입 SampleValue<T>을 확장한다고 선언됩니다.

SampleValue<T>SampleValue<Boolean>은 두 가지 유형이므로이 때문에 컴파일 오류가 발생합니다. forType 함수는 제네릭 형식 R을 반환하고자 다음과 같은 문으로 특정 유형을 반환 :

return new SampleBoolean(); 
2

이유는 조건부 컴파일러에 아무것도 증명하지 않는다는 것입니다.

당신이 여기에서 발생하는 혼란은 조건부을 포함한다 :이 체크와

if(Boolean.class.equals(clazz)) 

을, 당신은 TBoolean 것을 추론하고 있지만 컴파일러이 집행 방법이 없습니다. 컴파일러는이 검사가 TBoolean임을 보장한다고 암묵적으로 가정하지 않습니다.R extends SampleValue<T>T 동안 전혀 아무것도 할 수 있기 때문에 수표에도 불구하고, 따라서

(모든 컴파일러에 대한 equals이 방법의 맥락에서 알고 그것은을 boolean. 반환하다), RSampleBoolean는 호환되지 않는 유형이다.

나는 T을 기반으로하여 new SampleValue<T>을 반환 할 수있는 방법을 생각해 낼 수는 없지만 해결책을 제시하면이 답변을 편집 할 것입니다. 나는 그것에 대해 다른 사람들의 아이디어를보고 싶다.

+0

그의 인터페이스는 기능적 인터페이스이므로 아마도 lambdas를 사용하고 clazz.newInstance()를 사용하여 리플렉션을 통해 유형 T를 만들 수 있습니다. 유일한 단점은 기본 생성자가없고 예외를 처리해야하는 경우입니다. –

관련 문제