0

我无法弄清楚使用泛型执行此操作的正确方法。我有一个类,Foo它有一个通用的(Foo<class>)。然后我想要一张地图Map<String, Foo>。现在,我可以做到这一点,并将其添加Foo<String>为一个地图项和Foo<Integer>另一个。但是,当我使用 map 的 get 方法时,我只是得到一个Foo返回,并且无法再推断类型,所以如果我这样做:

String s = map.get("StringFoo")

我得到一个编译错误,必须做:

String s = (String) 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 —— 这是首先使用泛型的原因之一,并且Foo#getValue()会明确地返回一个 String。

于 2013-10-27T02:03:18.410 回答
3

这种结构在Java中其实并不少见,问题是泛型参数是仅编译时的特性,而map-retrieval是仅运行时的特性,所以编译器无法理解你的规则,而不是在某处提出警告。

实现这样的结构最安全的方法是通过包装类,它在逻辑上保证类型安全,而您所要做的就是SuppressWarnings("unchecked")在 getter 上抛出一个。

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错误类型的 a 与错误的Class对象放在一起,因此“未经检查”的强制转换永远不会失败。

于 2013-10-27T02:17:01.300 回答