【问题标题】:Using nested generic types in HashMap在 HashMap 中使用嵌套的泛型类型
【发布时间】:2018-06-09 14:04:17
【问题描述】:

我正在寻找一种在Map 的类型中使用泛型类型的Map 的方法,然后使用键和正确的类型检索那些。例如:

private final <T> Map<A<T>,B<T>> map = new HashMap<>();

public <T> B<T> getB(final A<T> a) {
  return map.get(a);
}

使用它的一个例子是:

final A<String> a = ...;
final B<String> b = getB(a);

这是否存在或有任何解决方法?

编辑:我知道我可以通过强制转换来解决它,但我想知道是否有一种更优雅的方式不需要我强制转换我检索到的每个值。

【问题讨论】:

  • 编译一下就行了。
  • 至于我认为您要问的问题,不,不可能以这种方式声明Map。可能请参阅stackoverflow.com/questions/44422685/… 了解一些解决方法示例(可能重复?)。
  • @zlakad 您认为该文档的哪一部分回答了这个问题?
  • 最好把我的问题通读几遍。如果你的问题需要重读几次,最好发邮件给@987654322 @你的问题,这样就更清楚了
  • @zlakad 我很感兴趣地等待您的替代答案。但是作为该库的用户,如果编写代码以强制执行类型安全,那么存在被抑制的未经检查的强制转换既不可见也不麻烦。我的意思是,您将相信(或以其他方式证明)get 方法会得到一些东西,而不是擦除硬盘驱动器,对吗?同样,您必须相信(或以其他方式证明)代码是类型安全的。

标签: java dictionary generics hashmap


【解决方案1】:

您不能以这种方式声明地图。基本上,Java 对此没有足够表达的类型系统。

但幸运的是,该语言以 casts 的形式提供了使用类型系统的逃生口。基本上,强制转换是一种提供编译器没有的类型信息的方法。然而,你有责任确保它实际上是类型安全的。

首先,用通配符类型声明地图:

private final Map<A<?>,B<?>> map;

然后,只将键/值对放入 满足约束的映射中:

<T> void put (A<T> key, B<T> value) {
  map.put(key, value);
}

当你再次取出元素时再进行投射:

@SuppressWarnings("unchecked") // Safe
<T> B<T> get(A<T> key) {
  return (B<T>) map.get(key);
}

关键是你可以比编译器更了解类型。如果您注意只放入可安全施放的对,则施放它们是安全的。 (您还需要确保equals 方法将类型考虑在内,因此A&lt;T&gt; 不等于A&lt;S&gt;,除非S == T)。

这基本上是一个“类型安全的异构容器”,如 Effective Java(第 3 版中的第 33 项)中所述。

我想知道是否有一种更优雅的方式不需要我强制转换我检索到的每个值。

一方面,您实际上并没有在运行时对 get 方法进行强制转换:这就是未经检查的强制转换的含义。

另一方面,泛型引入了 loads 的转换 - 基本上泛型只是一种避免手动插入转换的方法。因此,如果演员表出现问题(例如性能),您已经在很多地方观察到了这一点。

套用库布里克的话:别担心,爱演员。

【讨论】:

  • 一个很好的答案,我会赞成。唯一让我有点紧张的是当我看到类似A&lt;?&gt; 而不是A&lt;? super T&gt; 之类的东西时。我仍然认为最好(提前)知道KVMap&lt;K, V&gt; 中应该是什么。
【解决方案2】:

好吧,我被激怒了发布这个答案,作为对 OOP 原则的一种看法。

问题代表Map&lt;A&lt;T&gt;,B&lt;T&gt;&gt;,所以我的方法是这样做:

class A<T> {}
class B<T> {}

public class Answer {

    public static void main(String[] args) {

        Map<A, B> map = new HashMap<>();
        A<Integer> a = new A<>(); //very safe
        B<String> b = new B<>(); //very safe

        map.put(a, b); //very safe

    }

}

我承认,还有额外的工作,但是……

【讨论】:

  • 噢。我的眼睛。 . .
  • @Priv,如果你不喜欢它,请随意投反对票 - 我永远不会删除它......祝你好运。
  • 您实际上正在做与我所寻找的相反的事情。 Map&lt;A&lt;T&gt;,B&lt;T&gt;&gt; 表示A 中的TB 中的T 相同,也就是说,如果你有A&lt;String&gt;,你也必须有B&lt;String&gt;;我在帖子中还提到了一个方法&lt;T&gt; B&lt;T&gt; getB(A&lt;T&gt; a):如果你传递了一个A&lt;String&gt;,你总是会得到一个B&lt;String&gt;
  • @Priv,这不是真的。就这么简单...您可以声明B&lt;Integer&gt;B&lt;WHATEVER&gt;...
  • ^这就是我问的。就这么简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-29
  • 1970-01-01
  • 1970-01-01
  • 2019-03-10
相关资源
最近更新 更多