【问题标题】:Java - generics & wildcards & interface versus implementationJava - 泛型和通配符 & 接口与实现
【发布时间】:2013-10-08 17:55:17
【问题描述】:

我有一个关于 Java 泛型的问题。假设我有以下界面:

public static class Something<T> {
    public void set(T t) {
    }
}

public static interface Manager<T> {
    public void add(final String key, final Something<T> o);

    public Something<T> get(final String key);
}

使用示例:

final Manager<Number> m = ...;

m.add("key", new Something<Number>());
m.get("key").set(new Integer(5));

我还希望能够将Something&lt;Integer&gt;Something&lt;Double&gt;、...添加到Manager&lt;Number&gt;。我想说我必须更改 add-function 的签名:

public static interface Manager<T> {
    public void add(final String key, final Something<? extends T> o);

    public Something<T> get(final String key);
}

final Manager<Number> m = ...;

m.add("key", new Something<Integer>());
m.get("key").set(new Integer(5));

到目前为止,一切都很好。让我们看一下管理器的可能实现:

public static class ManagerImplementation<T> implements Manager<T> {
    protected HashMap<String, Something<T>> map = new HashMap<String, Something<T>>();

    public void add(final String key, final Something<? extends T> o) {
        map.put(key, o); // <--- here
    }

    public Something<T> get(final String key) {
        return map.get(key);
    }
}

这失败了,因为您无法将Something&lt;? extends T&gt; 添加到Map&lt;X, Something&lt;T&gt;&gt;。所以让我们改变一下:

public static class ManagerImplementation<T> implements Manager<T> {
    protected HashMap<String, Something<? extends T>> map = new HashMap<String, Something<? extends T>>();

    public void add(final String key, final Something<? extends T> o) {
        map.put(key, o);
    }

    public Something<T> get(final String key) {
        return map.get(key); // <--- here
    }
}

这失败了,因为map.get(key) 返回Something&lt;? extends T&gt;,而get 函数需要返回Something&lt;T&gt;,正如接口中定义的那样。

解决这个问题的常用方法是什么?

谢谢!

【问题讨论】:

  • 为什么不能把接口中的get方法也改成public Something&lt;? extends T&gt; get(final String key);呢?
  • @HariShankar 这将返回 Something&lt;? extends T&gt;,因此 OP 将无法通过此类引用向 set 发送任何内容(null 除外)。

标签: java generics


【解决方案1】:

在你的类中,你总是使用Something&lt;? extends T&gt;,因此在你的public get方法中,你必须将内部世界转换为外部世界格式。例如。您可以简单地将map.get(key) 的结果转换为Something&lt;T&gt;

return (Something<T>) map.get(key); // <--- here

【讨论】:

  • 我对泛型相当陌生。我一直认为,当泛型到位时,您可以避免强制转换。所以这不是真的吗?这只能通过使用强制转换来正确解决?
  • 从实用的角度来看,我的建议是:使用泛型,但要少用。通常,一级泛型(如'',没有扩展或超级)就足够了,更多的东西都过于复杂并使您的代码不可读。强调“通常”。 ;-)
  • 所以,换句话说,你是说对于外界/API,泛型必须符合预期(必要时使用通配符),但对于实现,最好保持为尽可能简单?
  • 这是一个哲学问题,但我希望泛型总是尽可能简单(当然,它们必须满足设计以及第 3 方 API)。看到太多类包含大量未记录的 (!) 泛型,没有程序员愿意使用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 2015-08-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多