2012-04-09 36 views
3

私はメソッドを持っている場合は、インスタンス戻り値の型

public INode getNode(final int offset); 

のために、私はそれは、例えば、メソッドの戻り値の型がジェネリックにする何かを追加しないと仮定します。

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

か私は何か見落としてますか?私はジェネリックな戻り値の型は、パラメータの1つが同じ型(またはスーパー/サブタイプ)の場合にのみ価値があると思いますか?

+0

これは、より多くの価値を追加する可能性がありますが、ジェネリックパラメータがクラスで定義されていれば、さらに価値があると思います。 – Joel

+0

質問は何ですか? 「何かを加えない」とはどういう意味ですか? –

答えて

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!) 
    } 
} 

ベストプラクティス:あなたはそれが実行時に正しい型になるだろう本当に確信している場合を除き、未チェックのキャストを使用しないでください。たとえば、次のプログラムを検討してください。

一般的な戻り値の型は、パラメータのいずれかが同じ型(またはスーパー/サブタイプ)の場合にのみ価値があると思いますか?

は、例えば、より多くの例があります。

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

または

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

または型の変数は単に見返りに型パラメータとして を表示さコリンの答え、の例型の消去のため許容される。

編集

私は型がありませんだと思う1は、ノードの正確な型にキャストしたい場合の方法を保存する(代わりにinstanceofはのそれに先行している)もちろん

ありそれはvisitor patternと呼ばれています。

+0

私たちはノードをINodeとして永続化しています。つまり、すべてのノードがそれを実装しなければならないので、インタフェースINodeのものです。次に、 "構造的"ノード用のインターフェースIStructNodeがあります。トランザクションカーソルは上記のメソッドを提供します。例えば、moveTo(nodeID)は内部的にgetNode(offset)を呼び出します。別の方法は、ノードをINodeとして、getStructuralNode()をIStructNodeとして、またはヌルオブジェクトパターンを実装する「NullNode」でラップするgetNode()です。私はノードの正確なタイプにキャストしようとした場合、型を保存する方法はないと思う(instanceofの代わりに先にする必要があります) – Johannes

+0

これはあなたの質問を修正するはずでしたか?その場合は、質問の編集ボタンを使用してください。それによって、あなたは修正を構造化してフォーマットすることもできます。 – meriton

+0

はい、確かに、訪問者パターン;-)私は約1年前にそれを実装しましたが、ちょうどそれについて考えなかった...ああ。 – Johannes

1

この例では、戻り値をキャストする実装の開発者(T)を強制する以外は実際に値を追加しません。 (Tの値を取得する方法がない限り、Tを返す別のメソッドを呼び出す必要があるので、キャストをさらに少し動かすだけです。

あなたは私たちを見せているケース


を総称が有用であることができる唯一の戻り値に適用されるいくつかのケースがあります。たとえば:。。これは、あなたがオブジェクトを作成することができます

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

CollectionTキャストする必要はありません。

それとも、Collectionsから(前記物体は、ジェネリックを使用する場合、主に動作します)彼のオブジェクトをキャストするために実装を行っている開発者、たとえばたい場合:

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

資源: