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

和之间有什么区别?

陆仲渊
2023-03-14
问题内容

在此示例中:

import java.util.*;

public class Example {
    static void doesntCompile(Map<Integer, List<? extends Number>> map) {}
    static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

    static void function(List<? extends Number> outer)
    {
        doesntCompile(new HashMap<Integer, List<Integer>>());
        compiles(new HashMap<Integer, List<Integer>>());
    }
}

doesntCompile() 无法编译为:

Example.java:9: error: incompatible types: HashMap<Integer,List<Integer>> cannot be converted to Map<Integer,List<? extends Number>>
        doesntCompile(new HashMap<Integer, List<Integer>>());
                      ^

compiles()被编译器接受。

这个答案说明唯一的区别是,与不同<? ...>,它<T...>允许您稍后引用类型,似乎并非如此。

是什么区别<? extends Number>,并<T extends Number>在这种情况下,为什么不第一编译?


问题答案:

通过使用以下签名定义方法:

static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

并像这样调用它:

compiles(new HashMap<Integer, List<Integer>>());

在jls§8.1.2中,我们发现(有趣的部分被我加粗了):

通用类声明定义了一组参数化类型(第4.5节), 每种可能通过类型arguments调用类型参数节的类型 。所有这些参数化类型在运行时共享同一类。

换句话说,将类型T与输入类型进行匹配并进行分配Integer。签名将有效地变为static void compiles(Map<Integer, List<Integer>> map)

关于doesntCompile方法,jls定义了子类型化规则(第4.5.1节,由我加粗):

如果在以下规则的自反和传递闭包中,证明T2表示的类型集是T1表示的类型集的子集,则类型自变量T1包含另一个类型自变量T2,写为T2 <=
T1。其中<:表示子类型(§4.10)):

  • ?扩展T <=?如果T <:S则扩展S

  • ?扩展T <=?

  • ?超级T <=?如果S <:T则为超级S

  • ?超级T <=?

  • ?超级T <=?扩展对象

  • T <= T

  • T <=?延伸T

  • T <=?超级T

这意味着,? extends Number确实包含Integer,甚至List<? extends Number>包含List<Integer>,但Map<Integer, List<? extends Number>>and
并非如此Map<Integer,List<Integer>>。在该SO线程中可以找到有关该主题的更多信息。您仍然可以?通过声明期望使用以下子类型来使带有通配符的版本起作用List<? extends Number>

public class Example {
    // now it compiles
    static void doesntCompile(Map<Integer, ? extends List<? extends Number>> map) {}
    static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

    public static void main(String[] args) {
        doesntCompile(new HashMap<Integer, List<Integer>>());
        compiles(new HashMap<Integer, List<Integer>>());
    }
}


 类似资料:
  • 问题内容: 今天,我按照一些说明在Linux中安装软件。有一个脚本需要首先运行。它设置一些环境变量。 指令告诉我要执行,但是我执行错误了。因此未设置环境。最后,我注意到了这一点并继续进行。 我想知道这两种调用脚本方法的区别。我对Linux完全陌生,所以请尽可能详细。 问题答案: 运行脚本,将启动一个新的运行脚本的外壳。新的外壳程序不会影响启动脚本的父外壳程序。 是的简写形式,它将在当前shell中

  • 问题内容: 我刚开始使用Spring。我遇到了很多教程。我看到使用更多的例子比。我查看了Spring文档,但无法弄清楚使用其中一个的好处。有人可以提供一些解释吗? 问题答案: 是的便捷子类。 JavaDoc描述了一些添加的属性,这些属性在某些情况下可能有用: UrlBasedViewResolver的便利子类,它支持InternalResourceView(即Servlet和JSP)以及诸如Jst

  • 问题内容: 我刚刚看到了包含标签的CSS代码。我看着MDN看看是什么,但我真的不明白。 有人可以解释它是如何工作的吗? 它会在我们通过CSS选择之前创建DOM元素吗? 问题答案: 根据这些文档,它们是等效的: 唯一的区别是CSS3中使用了双冒号,而单冒号是旧版本。 推理: CSS 3中引入了:: before表示法,以便在伪类和伪元素之间建立区别。浏览器还接受:在CSS 2中引入的表示法。

  • 问题内容: 以下哪个更好? 要么 我知道的唯一区别是,当“ a”为null时,第一个返回false,而第二个抛出异常。除此之外,它们是否总是给出相同的结果? 问题答案: 使用时,你需要B在编译时知道类。使用时可以是动态的,并且可以在运行时更改。

  • 问题内容: 根据MDN: 在许多情况下,revert关键字的工作原理与未设置的关键字完全相同。唯一的区别是属性具有由浏览器或用户创建的自定义样式表(在浏览器侧设置)设置的值。 我不了解浏览器和自定义样式表。浏览器和自定义样式表也都可以替换,对吗? 问题答案: 从MDN: 如果未设置CSS关键字从其父级继承,则将其重置为继承的属性,如果不是,则将其重置为初始值。换句话说,在第一种情况下,其行为类似于

  • 问题内容: 从文档中,我们可以了解有关该功能的以下信息: 处理所有待处理的事件,调用事件回调,完成所有待处理的几何图形管理,根据需要重新绘制窗口小部件,并调用所有待处理的空闲任务。此方法应谨慎使用,因为如果从错误的位置(例如,从事件回调内部,或者从可以以任何方式从事件回调中调用的函数等)调用,则可能导致真正令人讨厌的竞争状况。 )。如有疑问,请改用。 另一方面,关于此功能: 调用所有待处理的空闲任