当前位置: 首页 > 面试题库 >

嵌套通配符

惠野
2023-03-14
问题内容

发现了有关使我烦恼的无限制通配符的事实。例如:

public class Test {

      private static final Map<Integer, Map<Integer, String>> someMap = new HashMap<>();

      public static void main(String[] args) {
         getSomeMap();
      }

      static Map<?, Map<?, ?>> getSomeMap() {
         return someMap;  //compilation fails
      }
}

尽管可以使用Map<?, ?>Map<?, Map<Integer, String>>返回类型,但失败。

有人可以告诉我确切原因吗?提前致谢。

更新资料

我认为,对于此问题,我似乎理解并最简单的解释(忽略所有这些复杂的规则)是Capture
Conversion(link)中的最后一个注释:Capture conversion is not applied recursively.


问题答案:

了解通配符类型的含义很重要。

您已经了解了,您可以将您Map<Integer, Map<Integer, String>>Map<?, ?>as Map<?, ?>隐式指定为任意类型,而对于任何可能引用了声明的type的人来说都是未知的Map<?, ?>。因此,您可以将 任何 地图分配给Map<?, ?>

相反,如果你有一个Map<?, Map<?, ?>>它有一个未知的密钥类型,但值类型是
知道。它的Map<?,?>类型,还记得上面的信息,可以与被分配 任何 地图。

因此,以下代码是合法的:

Map<?, Map<?, ?>> map=new HashMap<>();
map.put(null, Collections.<String,String>singletonMap("foo", "bar"));
map.put(null, Collections.<Double,Integer>singletonMap(42.0, 1000));
map.put(null, Collections.<Object,Boolean>singletonMap(false, true));

在这里,我们放置了一个null键,因为对于键,我们put什么都做不到,而是将任意类型的映射作为值,因为这就是值类型的Map<?, ?>含义:可以从任意映射中分配值。注意,通过遍历条目,我们还可以将具有非null键的其他条目设置为任意映射。

因此,我非常确定您不希望将您的分配Map<Integer, Map<Integer, String>>给a Map<?, Map<?, ?>>并在以后发现不Map<Integer, String>作为值的任意映射,并且您很高兴编译器不允许这样做。

您实际要做的是将地图分配给键和值类型都未知的类型,但仍然告诉您值是地图:

Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, ? extends Map<?, ?>> map=someMap;

在通用类型系统中,它Map<Integer, String>是的子类型,Map<?, ?>因此您可以将其分配给Map<?, ?>? extends Map<?, ?>。此子类型关系与Stringto
的关系没有不同Object。您可以将任何值分配给String类型的变量Object但是如果您有一个Map<?,String>,则不能将其分配给,Map<?,Object>而只能Map<?, ? extends Object>由于相同的原因:映射应继续包含Strings作为值,而不是接收任意对象。

请注意,您可以解决此限制。你可以说:

Map<Integer, Map<Integer, String>> someMap = new HashMap<>();
Map<?, Map<?, ?>> map=Collections.unmodifiableMap(someMap);

由于返回的映射unmodifiableMap不允许进行任何修改,因此可以扩展键和值类型。Map<?, ?>查询映射时,包含的值具有指定的类型(即),但是尝试放入任意映射值(尽管编译器未拒绝),但将在运行时拒绝。



 类似资料:
  • 问题内容: 为什么这样做: 虽然这会产生类型不匹配错误: 为什么是这样?是否有办法解决此问题,而不使用原始类型? 问题答案: 尝试 注意:请注意,当您使用类似List的集合时,您只能在“只读”模式下使用它(添加空值除外)。

  • 问题内容: 我对Java泛型中的嵌套嵌套通配符有疑问。 这是一个常见的情况: 这是标准的Java泛型,工作正常。 但是,如果通配符嵌套,它将不再起作用: 这会导致编译器错误。 我已经尝试了各种强制类型转换和通配符置换,但是无法正常工作。我不记得以前曾见过此问题,并且我使用泛型已有多年。我是否太累了,缺少明显的东西? 问题答案: 所以问题是,可以实现为: 您需要确定您的实际意思。 大概是这样的:

  • 目前我有这个阵列= 条件: 如果每个嵌套数组index2都相同,那么我想用[0.0 1.0,1.0 2.0,2.0 3.0,3.0 4.0] = [1.0,3.0,5.0,7.0]来求和 我想要的最终结果:[[“efg”, [1.0, 3.0, 5.0, 7.0], “测试”]] 有什么方法或建议来获得这个结果吗?

  • 问题内容: 这样编译(1.6) 但这不是 的错误 有人可以解释为什么吗?谢谢 编辑:编辑为结果 问题答案: 因为这会破坏类型安全性:

  • 问题内容: 在以下示例中: 为什么对second(b)的调用有效,但对third(a)的调用却无效 ? 我收到以下错误: 问题答案: 如果您希望能够使用自变量进行调用,则需要将签名更改为此: 将上面的工作,因为不像,是兼容。这样想: 推理很简单。如果你有 然后,如果您 可以这样 调用该方法:

  • 问题内容: 我想在我的api中提供以下内容: 所以我这样写: 但是java无法解决。 随着代替它的工作原理,但第二个实际上是多余的“事业AbtractThing已定义的类型。所以我喜欢摆脱它。 问题答案: 你不能摆脱它。第二个不是多余的。您希望编译器将第一个解释为类型参数,但事实并非如此。您也可以这样写: 请注意,在这种情况下,它是一个具体的类,而不是类型参数。将此与以下内容进行比较: 请注意,它