3

たとえば、メソッドがある場合

public INode getNode(final int offset);

たとえば、メソッドの戻り値の型をジェネリックにするために何かを追加しないと思います。

public <T extends INode> T getNode(final int offset);

それとも私は何かを逃しましたか?パラメータの1つが同じタイプ(またはスーパー/サブタイプ)である場合、ジェネリック戻り値のタイプは価値があると思いますか?

4

2 に答える 2

4
public <T extends INode> T getNode(final int offset);

これは呼び出し元に追加情報を提供しないだけでなく、完全に危険です: そのメソッド シグネチャを実装する唯一の方法は、チェックされていないキャストを使用することです。これは、メソッドの型パラメーターが呼び出し元によって指定されるため、タイプ セーフにすることはできません。 (型推論を通じて明示的または暗黙的に)、型パラメーターはこのメソッドの実装では使用できません。たとえば、次のプログラムを考えてみましょう。

class NodeCollection {
    private INode[] nodes = new INode[42];

    public <T extends INode> T getNode(final int offset) {
        return (T) nodes[offset];
    }

    public <T extends INode> setNode(final int offset, T node) {
        nodes[offset] = node;
    }
}

class ANode implements INode {}
class BNode implements INode {
    void foo();
}

public class Test {
    public static void main(String[] args) {
        NodeCollection nc = new NodeCollection();
        nc.setNode(0,new ANode());
        BNode b = nc.getNode(0); // throws ClassCastException (sic!)
    }
}

ベスト プラクティス:実行時に型が正しいことが本当に確実でない限り、チェックされていないキャストを使用しないでください。

パラメータの1つが同じタイプ(またはスーパー/サブタイプ)である場合、ジェネリック戻り値のタイプは価値があると思いますか?

たとえば、次のような場合があります。

public <T> T getFavorite(Class<T> clazz) {
    return clazz.cast(favorites.get(clazz));
}

また

interface List<E> {
    E get(int index);
}

または Colin's answer の例では、型変数は戻り値の型の型パラメーターとしてのみ表示されますが、これは型消去のために受け入れられます。

編集

ノードの正確なタイプにキャストしたい場合、タイプを保存する方法はないと思います(インスタンスの代わりに、それを先行させる必要があります)

もちろん、ビジターパターンというものがあります。

于 2012-04-09T21:43:48.427 に答える
1

あなたが与える例では、実装の開発者に戻り値をキャストさせることを除いて、実際には値を追加しません( in T)。(値を取得する方法がない限りT、そのためには を返す別のメソッドを呼び出す必要があるTため、キャストを少し進めただけです。

あなたが私たちに見せている場合、本当に良い考えではありません。


戻り値にのみ適用されるジェネリックが役立つ場合がいくつかあります。例えば:

public static <T> Collection<T> generateCollection() {
    return new ArrayList<T>();
}

これにより、キャストを行わなくてものオブジェクトCollectionを作成できます。T

または、実装を行っている開発者にオブジェクトをキャストさせたい場合 (ほとんどの場合、オブジェクトがジェネリックを使用している場合に機能します)、例Collections:

public static final <T> Set<T> emptySet() {
    return (Set<T>) EMPTY_SET;
}

資力:

于 2012-04-09T21:31:16.950 に答える