0

ジェネリックでこれを行う適切な方法がわかりません。Fooジェネリック ( ) を持つクラスがありFoo<class>ます。次に、のマップが必要ですMap<String, Foo>Foo<String>これで、 1 つのマップ アイテムとして追加したり、別のマップ アイテムとして追加したりできますFoo<Integer>。ただし、マップの get メソッドを使用すると、単にFooback を取得し、型を推測できなくなるため、次のようにします。

String s = map.get("StringFoo")

コンパイルエラーが発生したため、次のことを行う必要があります。

文字列 s = (文字列) map.get("StringFoo")

キャストを回避するためにこのようなことを行うための良いパターンは何ですか。そもそもそれがジェネリックの目的であるためです。のようなことができるかもしれませんがMap<String, Foo<?>>、その方法はありますか?

私のコードの詳細は次のとおりです。これはディレクトリに配置してjavac *.java && java Main実行できます。

Foo.java にジェネリック Java クラスがあります。

public class Foo<T>
{
    T value;

    public T getValue()
    {
        return this.value;
    }

    public void setValue(T t)
    {
        this.value = t;
    }
}

今、Main.java に次のテスト クラスがあります。

import java.util.Map;
import java.util.HashMap;

public class Main
{
    public static void main(String[] a)
        {
            Foo<String> fooStr = new Foo<String>();
            fooStr.setValue("TEST 123");

            Foo<Integer> fooInt = new Foo<Integer>();
            fooInt.setValue(314159);

            Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();

            mapOfFoo.put("Strings", fooStr);
            mapOfFoo.put("Integer", fooInt);

            System.out.println("All set");

            String s = mapOfFoo.get("Strings").getValue();

            System.out.println("Got: " + s);

        }
}

これをコンパイルすると、次のエラーが発生します。

Main.java:21: error: incompatible types
            String s = mapOfFoo.get("Strings").getValue();
                                                       ^
  required: String
  found:    Object
1 error

Main.java でこれを行うと、次のように動作します。

import java.util.Map;
import java.util.HashMap;

public class Main
{
    public static void main(String[] a)
        {
            Foo<String> fooStr = new Foo<String>();
            fooStr.setValue("TEST 123");

            Foo<Integer> fooInt = new Foo<Integer>();
            fooInt.setValue(314159);

            Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();

            mapOfFoo.put("Strings", fooStr);
            mapOfFoo.put("Integer", fooInt);

            System.out.println("All set");

            String s = (String)mapOfFoo.get("Strings").getValue();

            System.out.println("Got: " + s);

        }
}

このようなもののベストプラクティスが何であるかはわかりません。誰か提案はありますか?

4

2 に答える 2

4

Map 宣言と構築で非ジェネリック Foo を使用しているようです。代わりにこれ:

Map<String, Foo> mapOfFoo = new HashMap<String, Foo>();

これでなければなりません:

Map<String, Foo<String>> mapOfFoo = new HashMap<String, Foo<String>>();

そうすれば、String にキャストする必要がなくなります。これは、そもそもジェネリックを使用する理由の 1 つであり、Foo#getValue()明確に String を返します。

于 2013-10-27T02:03:18.410 に答える
3

この種の構造は、実際には Java で必要とされることは珍しくありません。問題は、ジェネリック パラメーターがコンパイル時のみの機能であり、マップ検索が実行時のみの機能であるため、コンパイラが理解する方法がないことです。あなたのルールであり、それについてどこかで警告を出さないでください。

このような構造を実装する最も安全な方法は、型の安全性を論理的に保証するラッパー クラスを使用することですSuppressWarnings("unchecked")

public class FooMapper {

  private Map<Class<?>, Foo<?>> fooMap = new HashMap<>();

  public <T> void setFoo(Class<T> clazz, Foo<T> foo) {
    fooMap.put(clazz, foo);
  }

  @SuppressWarnings("unchecked")
  public <T> Foo<T> getFoo(Class<T> clazz) {
    return (Foo<T>) fooMap.get(clazz);
  }

}

Fooこのラッパーは、間違った型の を間違ったオブジェクトに配置できないことを保証するClassため、「チェックされていない」キャストが失敗する可能性はありません。

于 2013-10-27T02:17:01.300 に答える