2016-10-05 14 views
8

私はできるだけ少ないコード量でこの問題を凝縮しようとしました。戻り値のJava型パラメータの問題

私は、データベーステーブルのように、とTableのクラスを持つテーブル構造を定義しました。 A Tableは基本的にのリストです。私はサブクラスがTableとという特定のフレーバーを定義し、あるタイプの行を互換性のない型に入れるという不適切な試みをキャッチするようにします。

抽象Agentクラスは、パラメーターを取り、タイプTの行を取るテーブルを返すメソッドを提供します。私は、私が持っている問題を説明する3つの方法を定義しました。

FinalAgentFinalTable、及びFinalRowクラスはAgentTable、及びクラスの実装を定義します。最終的には、私が望むのはmethod2aです。これはパラメータのリストを取り、タイプFinalTableのテーブルを返します。

public abstract class Row {} 
public abstract class Table<T extends Row> {} 
public abstract class Agent { 
    public <T extends Row> Table<T> method1(List<String> parameter) { 
     return null; 
    } 
    public <T extends Row> Table<T> method2a(List<String> parameter) { 
     return null; 
    } 
    public <T extends Row> Table<T> method2b(String parameter) { 
     return null; 
    } 
} 

public class FinalRow extends Row {} 
public class FinalTable extends Table<FinalRow> {} 
public class FinalAgent extends Agent { 
    @Override 
    public <T extends Row> Table<T> method1(List<String> parameter) { 
     return null; 
    } 
    @Override 
    public FinalTable method2a(List<String> parameter) { 
     return null; 
    } 
    @Override 
    public FinalTable method2b(String parameter) { 
     return null; 
    } 
} 
一番下に

FinalAgentコンパイルの

  • method1が、私は、メソッドを呼び出すためにTable<FinalRow> t1 = new FinalAgent().method1(null);を記述する必要があります。 FinalAgent
  • method2a私は私が実際に(私はFinalTable t2a = new FinalAgent().method2a(null);を書きたい)戻っています何を反映するためにFinalTableに戻り値の型を変更しましたが、コンパイラはエラーを生成します。型FinalAgentの方法method2a(リスト)をオーバーライドまたは実装する必要がありますスーパータイプメソッド
  • method3パラメータをListからStringに変更しました。このメソッドはOKをコンパイルしますが、少なくとも私は型の安全に関する警告を出します。

だから、最終的には、質問:それはFinalAgentmethod2amethod2bがコンパイルんまだコンパイルされませんコンパイラのバグですか?

私もやっているかもしれませんが、私がやっていることをする良い方法がありますか?

+0

@ElliottFrisch? – shmosel

+0

@shmosel私の誤りは、私は 'FinalTable'の宣言でジェネリック型を見逃しました。 –

+0

それは不思議な矛盾です。 – shmosel

答えて

8

なぜメソッドをパラメータ化するのかは不明です。 Table<T>を返すと約束していますが、タイプ消去のため実行時にメソッドがTを識別できません。おそらく、全体ではなくAgentクラスをパラメータ化する:

public abstract class Agent<T extends Table<?>> { 
    public T method1(List<String> parameter) { 
     return null; 
    } 
    public T method2a(List<String> parameter) { 
     return null; 
    } 
    public T method2b(String parameter) { 
     return null; 
    } 
} 

public class FinalAgent extends Agent<FinalTable> { 
    @Override 
    public FinalTable method1(List<String> parameter) { 
     return null; 
    } 
    @Override 
    public FinalTable method2a(List<String> parameter) { 
     return null; 
    } 
    @Override 
    public FinalTable method2b(String parameter) { 
     return null; 
    } 
} 

あなたの最初の質問については、私は矛盾やmethod2bに警告メッセージの意味を理解することはできません。単一の場所でメソッドのパラメータを使用して

1

パラメータがAgentでそのような方法では

通常不要であることを意味し、FinalAgentは罰金コンパイル:

public Table<? extends Row> method2a(List<String> parameter) { 
    return null; 
} 
public Table<? extends Row> method2b(String parameter) { 
    return null; 
} 
1

は、これは、生タイプの直接の結果です。

  • method1はまだ一般的な方法です。問題はありません。
  • method2bはもう一般的な方法ではありませんが、Agentでメソッドをオーバーライド:(未確認の変換のためにかかわらず、安全上の警告を除く、)何の問題
  • method2aはもう一般的な方法ではないではありませんが、何も
  • 上書きされることはありません

method2aコンパイル後、FinalAgentからこのように宣言見られている:

public Table method2a(List parameter) 

しかしFinalAgentで、次のように定義された:

public FinalTable method2a(List<String> parameter) 

そして今、あなたがあるがを立ち往生。

public interface Foo 
{ 
    public void bar(List a); 
} 

public class FooChild implements Foo 
{ 
    @Override 
    public void bar(List<String> a) 
    { 
    } 
} 

それはName clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List) of type Foo but does not override it

別の例を示しますThe method bar(List<String>) of type FooChild must override or implement a supertype method

public interface Foo 
{ 
    public void bar(List a); 
} 

public class FooChild implements Foo 
{ 
    public void bar(List<String> a) 
    { 
    } 
} 

与える:同じ消去が、ここでは正しくmethod2a

を上書きすることはありませんが、簡単な例です。このコードは罰金コンパイル:

public interface Foo 
{ 
    public void bar(List<String> a); 
} 

public class FooChild implements Foo 
{ 
    public void bar(List<String> a) 
    { 
    } 
} 

この1にはない:

public interface Foo 
{ 
    public <T> void bar(List<String> a); 
} 

public class FooChild implements Foo 
{ 
    public void bar(List<String> a) 
    { 
    } 
} 

それはそれは生タイプと見られていると私たちは気づくことができる、とすぐbarが一般的な方法になるとName clash: The method bar(List<String>) of type FooChild has the same erasure as bar(List<String>) of type Foo but does not override it

を与えます同じ問題。

生タイプの問題の異なる例:生タイプだName clash when overriding method of generic class

+0

生のタイプはどこにありますか?チェックされていないコンバージョンはなぜですか? – shmosel

+0

ジェネリック型T – ToYonos

+0

の汎用メソッドであるため、 'method2a'は' Agent'の生の型で見られます。チェックされていない変換は 'FinalTable'から来ます。コンパイラは 'method2b'の' テーブル 'であることを確認することはできません – ToYonos