5

自己参照ジェネリックをキャストできない理由がわかりません。

Java では、自己参照ジェネリックがあります。たくさんのもの( Intent) と、それらのもの ( ) を検索 (解決) するための戦略がありResolutionStrategyます。

自己参照Intent型は以下で定義されます。コンパイル時にResolutionStrategy、同じ意図を受け入れる のみを受け取ることができるクラスを定義したいと考えています。

public interface Intent<I extends Intent<I, R>, R extends Resolution>
{
    void resolve(ResolutionStrategy<I, R> strategy);

    R getResolution();
}

したがって、解決戦略は次のとおりです。

public interface ResolutionStrategy<I extends Intent<I, R>, R extends Resolution>
{
    R resolve(I intent);
}

したがって、これらの のリストを操作しているときは、Intentそれらが何であるかはあまり気にしません。ただし、ドメイン モデルで具体的なものを表す特定の型を作成したいと考えています。次に例を示します。

public class OrgIntent implements Intent<OrgIntent, IdentifiableResolution>
{
    public final String name;

    public OrgIntent(String name)
    {
        this.name = name;
    }

    @Override
    public void resolve(ResolutionStrategy<OrgIntent, IdentifiableResolution> strategy)
    {
        // Do stuff
    }

    @Override
    public IdentifiableResolution getResolution()
    {
        //Return resolution got from strategy at some point in the past
        return null;
    }
}

IdentifiableResolutionの単純で面白くない実装ですResolution

これまでのところすべて順調です。次に、これらの s の優れたグラフを作成し、Intentそれらを反復処理して、それぞれを a に渡して、ResolutionStrategyFactoryそれらを解決するための関連する戦略を取得する計画です。ただし、OrgIntentリストに追加するのに十分な一般的なものにキャストすることはできません!

private <I extends Intent<I, R>, R extends Resolution> DirectedAcyclicGraph<Intent<I, R>, DefaultEdge> buildGraph(Declaration declaration) throws CycleFoundException
{
        DirectedAcyclicGraph<Intent<I, R>, DefaultEdge> dag = new DirectedAcyclicGraph<>(DefaultEdge.class);
        // Does not compile
        Intent<I, R> orgIntent = new OrgIntent("some name");
        // Compiles, but then not a valid argument to dag.addVertex()
        Intent<OrgIntent, IdentifiableResolution> orgIntent = new OrgIntent("some name");
        // Compiles, but then not a valid argument to dag.addVertex()
        OrgIntent orgIntent = new OrgIntent("some name");

        //Then do this
        dag.addVertex(orgIntent);
        ...

私が宣言すべきものはありorgIntentますか?

アップデート

@zapl のおかげで、メソッド定義のジェネリック型パラメーターが完全なニシンであることに気付きました。

これはコンパイルされますが、おそらくIntent、最初のジェネリック型として古いナンセンスを持つようにジェネリック化された を何らかの形で持つことができることを意味しますか?

private DirectedAcyclicGraph<Intent<?, ? extends Resolution>, DefaultEdge> buildGraph(Declaration declaration) throws CycleFoundException
{
    DirectedAcyclicGraph<Intent<?, ? extends Resolution>, DefaultEdge> dag = new DirectedAcyclicGraph<>(DefaultEdge.class);
    OrgIntent orgIntent = new OrgIntent("some name");
    dag.addVertex(orgIntent);
4

1 に答える 1

2

コメントでzaplが示唆しているように、ジェネリックは、説明しているパターンを処理するのに十分な強力な型保証を提供しません。特に、Java ジェネリックは具体化されていないため、JVM がOrgIntentより一般的な型 ( ) にキャストされた後に、より具体的な型 ( )を回復する方法はありませんIntent<I, R>。ジェネリック型情報は実行時に失われるため、JVM は具体的な生の型にしか依存できません ( Intent)。

これは、たとえば、ジェネリック シグネチャが異なるが具象シグネチャが同じ 2 つのメソッドを定義できないことと同じ理由です。foo(List<String>)どちらも実行時foo(List<Integer>)に単純になるfoo(List)ため、コンパイラは同じメソッドで 2 つのメソッドを定義することを許可しません。クラス。

大まかに言えば(そして、私はあなたのユースケースをより正確に理解するのに十分なほどよく理解していないのではないかと心配しています)解決策は、関連付けられたClassオブジェクトまたはTypeToken. たとえば、次の署名を機能させることができる場合があります。

R resolve(Class<I> intentClass, I intent);

有効な Java 項目 29: タイプセーフな異種コンテナーを検討する で提供されているアドバイスも役立つはずです。

ただし、[固定数の型パラメーターよりも] 柔軟性が必要な場合もあります.... アイデアは、コンテナーの代わりにキーをパラメーター化することです。次に、パラメーター化されたキーをコンテナーに提示して、値を挿入または取得します。ジェネリック型システムは、値の型がそのキーと一致することを保証するために使用されます。

...

Java の型システムは [キーと値の間の型の関係] を表現できるほど強力ではありません。しかし、私たちはそれが真実であることを知っており、お気に入りを取得するときにそれを利用しています.

于 2016-06-02T04:36:57.813 に答える