2017-03-26 9 views
3

一般的なコードで特定のセッターを呼び出したい。もちろん、私はケース・ステートメントに頼ることができますが、それは大きく成長するので、私はマップを好む。マップを使用してオブジェクト上のアクションを呼び出す方法

これは私がこれまでに思い付いたものです:

public class Tester { 

private static final Map<String, Setter<Target, ?>> MY_SETTERS = new HashMap<>(); 
static { 
    MY_SETTERS.put("SOURCE1", (Target t, Source1 s) -> t.setSource1(s)); 
    MY_SETTERS.put("SOURCE2", (Target t, Source2 s) -> t.setSource2(s)); 
} 

@FunctionalInterface 
private interface Setter<T, S> { 

    void set(T target, S source); 
} 

public static void main(String[] args) { 

    Target t = new Target(); 
    MY_SETTERS.get("SOURCE1").set(t, new Source1()); 
}} 

はしかし、これは私に、「互換性のない型を与える:CAP#1は、新鮮な型の変数ですソース1は、#1 をキャップに変換することはできません: CAP#1はオブジェクトをキャプチャから拡張しますか? "

なぜその失敗私は理解しています。しかし、ケースステートメントに頼ることなくこれを行うためのエレガントな方法はありますか?

+0

は、それだけですべての 'セッター'を明示的にゲッターを書くために論外ですか?ですから、あなたは 'MY_SETTERS.getSource1Setter()。set(t、new Source1());'でちょうど立ち往生します。もちろん、これには欠点があります。これは、毎回あなたがどのセッターを扱っているかを正確に知る必要があります。 – Obicere

+0

@Obicere ..問題は、私の実際のcasusはJAXBが大量のエントリを持つ選択クラスを生成したことです。処理ステップの残りの部分が同じであるため、それらを汎用的に扱いたい。 – sjaak

答えて

1

ためのマップでそのワイルドカード型の、あなたはどこかで線を描画する必要があります。これは少し醜いですが、それは私が時々何をすべきかです:

はあなたの要求された型にSetterをキャストしますジェネリックヘルパーメソッドを定義します。

public static <T, S> Setter<T, S> getSetter(String id) { 
    return (Setter<T, S>) MY_SETTERS.get(id); 
} 

は、このようなセッターを取得し、起動します

getSetter("SOURCE1").set(t, new Source1()); 

Javaがあなたの渡されたパラメータから型引数を推論し、呼び出し自体は罰金になります。あなたはそのチェックされていないキャストのためにコンパイラからの苦情を得るでしょう。

明らかに、あなたはあなたにそうあなたがClassCastExceptionを取得する得ることを期待するものである要求するものを絶対に確認する必要があります。例えば。あなたがSource1のためのセッターを取得するが、Source2でそれを呼び出すよう、以下を行うことは、言った例外が生成されます。

getSetter("SOURCE1").set(t, new Source2()); 
+0

これは[ヒープを汚染する]ための完全な方法です(https://docs.oracle.com/javase/tutorial/java/generics/nonReifiableVarargsType.html)。 –

+0

理由を詳しく教えてもらえますか?マップを変更していません。 – Justas

+0

明確な例で 'ClassCastException'の危険性を示しているので、私はdownvoteを削除しました。私はちょうどあなたが示したことを意味しました。 –

関連する問題