带参数的泛型方法与带通配符的非泛型方法

2023-12-20

根据Java 泛型常见问题解答中的此条目 http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ302B,在某些情况下,泛型方法没有使用通配符类型的等效非泛型方法。根据那个答案,

如果方法签名使用多级通配符类型,则通用方法签名与其通配符版本之间始终存在差异。

他们给出了一个方法的例子<T> void print1( List <Box<T>> list),其中“需要相同类型的盒子列表”。通配符版本,void print2( List <Box<?>> list),“接受不同类型的盒子的异构列表”,因此不等效。

您如何解释以下两个方法签名之间的差异:

 <T extends Iterable<?>> void f(Class<T> x) {}
                         void g(Class<? extends Iterable<?>> x) {}

直观上,这些定义似乎应该是等效的。然而,调用f(ArrayList.class)使用第一种方法编译,但是调用g(ArrayList.class)使用第二种方法会导致编译时错误:

g(java.lang.Class<? extends java.lang.Iterable<?>>) in Test
    cannot be applied to (java.lang.Class<java.util.ArrayList>)

有趣的是,这两个函数都可以使用彼此的参数进行调用,因为以下代码可以编译:

class Test {
    <T extends Iterable<?>> void f(Class<T> x) {
        g(x);
    }
    void g(Class<? extends Iterable<?>> x) {
        f(x);
    }
}

Using javap -verbose Test, 我理解了f()具有通用签名

<T::Ljava/lang/Iterable<*>;>(Ljava/lang/Class<TT;>;)V;

and g()具有通用签名

(Ljava/lang/Class<+Ljava/lang/Iterable<*>;>;)V;

如何解释这种行为?我应该如何解释这些方法签名之间的差异?


嗯,根据规范,这两种调用都是不合法的。但为什么第一个会进行类型检查,而第二个则不会?

区别在于如何检查这些方法的适用性(参见§15.12.2 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2 and §15.12.2.2 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.2尤其)。

  • 对于简单的、非通用的g为了适用,论证Class<ArrayList>需要是一个子类型Class<? extends Iterable<?>>。这意味着? extends Iterable<?>需要contain http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.5.1-400 ArrayList,写成ArrayList <= ? extends Iterable<?>. Rules 4 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.5.1-400-D and 1 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.5.1-400-A可以传递应用,因此ArrayList需要是一个子类型Iterable<?>.

    通过去§4.10.2 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.10.2任何参数化C<...>是原始类型的(直接)子类型C. So ArrayList<?>是一个子类型ArrayList,但反之则不然。传递性地,ArrayList不是 的子类型Iterable<?>.

    Thus g不适用。

  • f是通用的,为了简单起见,我们假设类型参数ArrayList被明确指定。去测试f为了适用性,Class<ArrayList>需要是一个子类型Class<T> [T=ArrayList] = Class<ArrayList>。由于子类型是反射性的 http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.10-110, 那是真实的。

    还为f要适用,类型参数需要是在其范围内 http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.2-110-B。这并不是因为,正如我们上面所展示的,ArrayList不是 的子类型Iterable<?>.

那么为什么它还是能编译呢?

这是一个错误。继一个错误报告 https://bugs.eclipse.org/bugs/show_bug.cgi?id=127583#c2 and 后续修复 http://git.eclipse.org/c/jdt/eclipse.jdt.core.git/commit/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/TypeBinding.java?id=a25cead90931bbc9548552bec95aa6f79a389aa3JDT 编译器明确排除第一种情况(类型参数包含)。第二种情况仍然被愉快地忽略,因为 JDT 认为ArrayList是一个子类型Iterable<?> (TypeBinding.isCompatibleWith(TypeBinding)).

我不知道为什么 javac 的行为相同,但我认为出于类似的原因。您会注意到 javac 在分配原始数据时不会发出未经检查的警告ArrayList to an Iterable<?> either.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带参数的泛型方法与带通配符的非泛型方法 的相关文章

随机推荐

  • 如果端口对于多播组无关紧要,为什么 DatagramSocket.joinGroup() 方法采用 SocketAddress?

    我只是好奇 这是 API 错误吗 当您加入多播组时 您不使用端口 而只使用多播地址 IP 即多播组 对吗 使用 PORT 时是否会出现这种情况 这是否令人烦恼 这个问题最好重新表述为 为什么DatagramSocket joinGroup
  • Python 中 and 与多个 if 的效率

    在 if 语句中使用 and 与使用多个 if 语句在效率上有区别吗 换句话说 就像 if expr1 expr2 and expr3 expr4 dostuff 从效率的角度来看 则不同 if expr1 expr2 if expr3 e
  • selectOneMenu 的第二项加粗

    我有一个 selectOneMenu 其中包含一个州的所有城市 我已经创建了一个 sql 来将资本放在首位 但我想将其加粗以使其对使用它的人更明显 有没有办法将其加粗或采取其他措施以使第二个选项更加明显
  • 将 FindWindow 与多个根窗口一起使用

    所以我正在构建一个使用 win32 的 SendMessage 作为 IPC 的应用程序 我正在使用 FindWindow 根据 className 和 windowName 获取 hWnd 这一切都进展顺利 直到我想与一个与其他根窗口具有
  • 子域到端口重定向[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 5 天前 我创建了一个 AWS 实例来保存我的 jenkins 和 archiva 服务 我已经有自己的域 并创建了 DNS 子域jenk
  • XML FrameLayout 降低了我的 OpenGL SurfaceView 帧速率 (fps)

    我扩展了 GLSurfaceView 并实现了我自己的 GLSurfaceView Renderer 以创建我的第一个相对简单的 Android 2D OpenGLES 游戏 我一直在活动 onCreate 方法上使用以下代码来测试我的游戏
  • 我应该使用迭代器或描述符来保留边或顶点上的引用吗?

    我目前正在设计一个由 Boost Graph adjacency list 和引用此结构中的边或顶点的几个类组成的应用程序 我的问题是 维护对节点或顶点的引用的推荐方法是什么 我猜想在迭代器的情况下 对象访问速度更快 但迭代器可能会因图结构
  • F#,管道转发第一个参数

    与这个问题非常相似 F 管道第一个参数 https stackoverflow com questions 35716622 f pipe first parameter 我目前正在学习 F 和函数式编程 我想知道是否有一种简单的方法可以通
  • CollapsingToolbarLayout 仅在顶部时展开

    我对 AppBarLayout 和 CollapsingToolbarLayout 有一些问题 这是目前发生的情况 https www youtube com watch v z4yD8rmjSjU https www youtube co
  • 如何使用MySQL列别名进行计算?

    如何使用两个子查询中的列别名 lat 和 lng 来进行下面的距离计算 我基本上想做的是使用经度和纬度值计算两个位置之间的距离 但不知何故 我的别名在查询中无法使用 为什么 SELECT wp posts SELECT wp postmet
  • flutter中自定义路由事务错误

    我试图为屏幕实现自定义动画 但遇到错误 错误是 没有为类型 RouteSettings 定义 getter isInitialRoute 这是我的代码 class MyCustomRoute
  • 遍历层次结构对象c#

    如果我有一个像下面这样的课程 我如何遍历它直到它的属性 SomeObjects count 0 public class SomeObject public String Name get set public List
  • TSLint 摆脱缺失的空白

    我一直试图在互联网上搜索来解决这个问题 但没有成功 也许你可以帮助我 我收到 tslint 缺少空格 警告 内容如下 src app content content controller ts 中的警告 4 13 缺少空格 5 21 缺少空
  • 如何在Android Studio的CMakeLists.txt文件中设置版本脚本文件

    我在Android Studio中有一个ndk项目 我想通过这种方式控制导出的符号 set CMAKE SHARED LINKER FLAGS CMAKE SHARED LINKER FLAGS Wl version script D Pr
  • 使用移动网页检测 Android 应用程序是否已安装在设备上 - PHP 和 JS

    我有这样的要求 Android Pit 应用商店已经实现了类似的要求 我需要使用移动网页 PHP 和 JS 检查设备上是否已安装 Android 应用程序 如果安装则立即启动该应用程序 这些是Android坑使用的中间页面 当应用程序尚未安
  • tf.initialize_all_variables() 和 tf.global_variables_initializer() 之间有什么区别

    在Tensorflow官方网站上 它给出了解释tf initialize all variables and tf global variables initializer 功能如下 tf initialize all variables
  • 如何编写循环来重复代码?

    我是Python的初学者 我想重复这段代码 但我真的不知道如何在没有 goto 的情况下做到这一点 我试图了解循环 但不明白如何应用它们 import requests addr input vendor requests get http
  • 使用注释时如何声明 Spring bean autowire-candidate="false"?

    我在用 ComponentScan and Component定义我的春豆 我想要的是声明其中一个豆子是autowire candidate false 这可以通过 xml 中的此属性来完成 注释中没有等效的吗 我想要这个的原因是因为我有同
  • 服务参考的替代方案

    我正在尝试通过解决一些痛点来协助一个项目团队简化他们的工作 他们代码中的痛点之一是 他们通过服务引用 代理 使用 WCF 服务 即Visua Studio 2008 中的 添加服务引用 这会产生很多问题 包括部署开销 源控制获取更新代理的最
  • 带参数的泛型方法与带通配符的非泛型方法

    根据Java 泛型常见问题解答中的此条目 http www angelikalanger com GenericsFAQ FAQSections ProgrammingIdioms html FAQ302B 在某些情况下 泛型方法没有使用通