2017-04-10 13 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>を取得します。

私の推測では、リスト(兄弟)の祖先ではないリストが、私は上記の木の木が見えない。

誰かが何が起こっているのか、長い例がうまくいかない理由を説明してもらえますか?

更新:NB:あなたが戻ってきているRは、常にその実装Rである

+1

'AnotherSampleBooleanクラスを宣言してSampleValue {...}'を実装し、次に '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

...アイデアは、さまざまな種類の/他の支店場合は、いくつかのより多くを持っていることでしたが、コンパイラは文句始めたとき、私は停止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> 

EDIT(まだテストしていない)

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>は2種類あります。そのため、コンパイルエラーが発生します。 forType機能は、ジェネリック型Rを返すように望んでいる、あなたは、次の文を使用して特定の型を返す:

return new SampleBoolean(); 
2

理由は、あなたの条件は、コンパイラには何も証明していないということです。

あなたがここに持っている混乱はあなたの条件が含まれます。

if(Boolean.class.equals(clazz)) 

このチェックを使用すると、TBooleanですが、コンパイラはこれを強制する方法がないことを推測しています。コンパイラは、このチェックでTBooleanであることを暗黙に保証しません。(すべてのコンパイラはおよそequalsこのメソッドのコンテキストでを知っていることは、それはbooleanを返すということです。)

R extends SampleValue<T>Tながら、まったく何もすることができるので、したがって、あなたのチェックにもかかわらず、RSampleBooleanは互換性のないタイプです。

の返品を確実にする方法を考え出すことはできません。Tに基づいていますが、解決策を使用してこの回答を編集します。私はそれについて他の人からのアイデアを見たいと思っています。

+0

彼のインターフェースは機能的なインターフェースなので、おそらくlambdasを使用し、clazz.newInstance()を使ってリフレクションを介してタイプTを作成することができますが、唯一の欠点は、デフォルトのコンストラクタがなく、例外を処理する必要がある場合です。 –

関連する問題