错误的泛型转换没有 ClassCastException [Java]

2024-04-15

看一下下面这个类的main方法:

public class Outer {
    static class A<T> {
        public A<T> a;
        public T t;

        public A() { a = null; }
        public A(T t) {
            a = (A<T>) new B();
            a.t = t;
        }
    }

    static class B extends A<Integer> {}

    public static void main(String[] args) {
        // A<String> c = new B();              // CREATION 1: would not work
        // A<String> b = (A<String>) new B();  // CREATION 2: would not work
        A<String> a1 = new A<>("str");         // CREATION 3: works (???)
        A<String> a2 = new A(0);               // CREATION 4: works (???)

        System.out.println(a1.a);    // CALL 1 -> Poly$B@...
        System.out.println(a1.t);    // CALL 2 -> null
        System.out.println(a1.a.a);  // CALL 3 -> null
        System.out.println(a1.a.t);  // CALL 4 -> str (???)
        System.out.println(a2.a.t);  // CALL 5 -> ClassCastException (???)
    }
}

显然,创建 1 和 2 将在编译时失败,因为无法进行强制转换。第三个对象创建是可能的,所以我没想到它会在编译时失败,但是:我期望(A<T>) new B();在运行时失败,因为B延伸A<Integer>并且不应该可以投射A<Integer> to A<String>(与创建2相同)...但是这里没有ClassCastException!?

不幸的是,《创造3》成功了。a1.a.t(哪一个是t的成员B对象)现在将存储字符串“str”!?所以一个B对象(意思是t属于类型Integer)可以存储Strings in Integer t!!?

还有一点:看看a2。正在尝试访问a2.a.t将产生 ClassCastException。这让我感到惊讶,因为在访问期间甚至没有演员表演 - 至少,这是我的想法......

所以我的问题简而言之是:

  1. 为什么创造 3 (/4) 是可能的?
  2. 为什么 B 对象能够在其通用整数变量 t 中存储字符串?
  3. 为什么调用 5 在运行时失败?

谢谢你!! :)


为什么创造 3 (/4) 是可能的?

Creation 3 是用于推断类型的“钻石”语法。所以new A<>和写作一样new A<String>.

因此我们可以用 Java 1.7 之前的长语法来替换它。

A<String> a1 = new A<String>("str");

这将通过以下构造函数,其中T was java.lang.String and t is a java.lang.String。请注意,在运行时只有一份此代码的副本,其原始类型为T being java.lang.Object.

    public A(T t) {
        a = (A<T>) new B();
        //  ^^^^^^ NB: This will at least give a rawtype warning
        //             as it causes heap pollution.
        a.t = t;
    } 

的类型a is A<T>在编译时和java.lang.Object删除了。两者的类型a.t and t is T在编译时和java.lang.Object删除了。因此它会在没有警告的情况下进行编译,并且在运行时无需进行强制转换检查。分配成功。

Creation 4 使用原始类型。你的编译器应该给出警告(使用-Xlint)。忽略这些警告可能会导致ClassCastException稍后的。泛型是真实虚拟机上的编译器“虚构”,它本质上遵循 Java 1.0 语言的规则。

为什么 B 对象能够在其通用整数变量 t 中存储字符串?

被擦除的类型t in A(因此B) is java.lang.Object因此,如果没有检查或检查不正确,可以存储任何引用类型。

为什么调用 5 在运行时失败?

物体位于a2.a.t is a java.lang.Integer. a2.a具有静态类型A<java.lang.String>所以静态类型a2.a.t is java.lang.String. javac将插入一个强制转换以检查返回的原始类型是否符合静态类型。在这种特殊情况下,IIRC,旧版本javac会错误地省略演员并使用println(java.lang.Object)过载而不是println(java.lang.String).

您可以使用javap -c -private看看到底在哪里checkcast已放置说明。

结论

确保您已打开警告。任何默认情况下没有打开它们的东西都有些可疑。不要忽略或抑制警告,尤其是有关原始类型的警告。

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

错误的泛型转换没有 ClassCastException [Java] 的相关文章

  • JDK 文档是语言规范的一部分吗?

    只有一名官员Java语言规范 https docs oracle com javase specs jls se8 html index html所有 Java 实现都必须遵守它 API文档怎么样 所有Java实现都需要遵守吗这个版本 ht
  • 如何在 Firebase 远程配置中从 JSON 获取值

    我是 Android 应用开发和 Firebase 的新手 我想知道如何获取存储在 Firebase 远程配置中的 JSONArray 文件中的值 String 和 Int 我使用 Firebase Remote Config 的最终目标是
  • 打印星号的 ASCII 菱形

    我的程序打印出这样的钻石 但只有当参数或菱形的每一面为4 例如如果我输入6 底部三角形的间距是错误的 我一直在试图找出答案 当参数改变时 底部的三角形不会改变 只有顶部的三角形会改变 它只适用于输入4 public static void
  • 在 Wildfly 中与 war 部署共享 util jar 文件

    假设我有一个名为 util jar 的 jar 文件 该 jar 文件主要包含 JPA 实体和一些 util 类 无 EJB 如何使这个 jar 可用于 Wildfly 中部署的所有 war 无需将 jar 放置在 war 的 WEB IN
  • 是否可以使用 Flying Saucer (XHTML-Renderer) 将 css 解析为类路径资源?

    我正在尝试将资源打包到 jar 中 但我无法让 Flying Saucer 在类路径上找到 css 我无法轻松构建 URL 来无缝解决此问题 https stackoverflow com questions 861500 url to l
  • 当客户端关闭连接时,Spring StreamingResponseBody 请求线程未清理

    我在控制器中有一个端点 它返回一个StreamingResponseBody 用于向客户端发送文件 其代码大致如下 RestController RequestMapping value api public class Controlle
  • 自动生成Flyway的迁移SQL

    当通过 Java 代码添加新模型 字段等时 JPA Hibernate 的自动模式生成是否可以生成新的 Flyway 迁移 捕获自动生成的 SQL 并将其直接保存到新的 Flyway 迁移中 以供审查 编辑 提交到项目存储库 这将很有用 预
  • 套接字的读写如何同步?

    我们创建一个套接字 在套接字的一侧有一个 服务器 在另一侧有一个 客户端 服务器和客户端都可以向套接字写入和读取 这是我的理解 我不明白以下事情 如果服务器从套接字读取数据 它在套接字中是否只看到客户端写入套接字的内容 我的意思是 如果服务
  • 从 GitHub 上托管的 Spring Cloud Config Server 访问存储库的身份验证问题

    我在 GitHub 上的存储库中托管配置 如果我将回购公开 一切都好 但如果我将其设为私有 我将面临 org eclipse jgit errors TransportException https github com my user m
  • 使用架构注册表对 avro 消息进行 Spring 云合约测试

    我正在查看 spring 文档和 spring github 我可以看到一些非常基本的内容examples https github com spring cloud samples spring cloud contract sample
  • HashMap 值需要不可变吗?

    我知道 HashMap 中的键需要是不可变的 或者至少确保它们的哈希码 hashCode 不会改变或与另一个具有不同状态的对象发生冲突 但是 HashMap中存储的值是否需要与上面相同 为什么或者为什么不 这个想法是能够改变值 例如在其上调
  • 在 SWT/JFace RCP 应用程序中填充巨大的表

    您将如何在 SWT 表中显示大量行 巨大是指超过 20K 行 20 列的东西 不要问我为什么需要展示那么多数据 这不是重点 关键是如何让它尽可能快地工作 这样最终用户就不会厌倦等待 每行显示某个对象的实例 列是其属性 一些 我想使用 JFa
  • QuerySyntaxException:无法找到类

    我正在使用 hql 生成 JunctionManagementListDto 类的实际 Java 对象 但我最终在控制台上出现以下异常 org hibernate hql internal ast QuerySyntaxException
  • Docker 和 Eureka 与 Spring Boot 无法注册客户端

    我有一个使用 Spring Boot Docker Compose Eureka 的非常简单的演示 我的服务器在端口 8671 上运行 具有以下应用程序属性 server port 8761 eureka instance prefer i
  • Android:无法发送http post

    我一直在绞尽脑汁试图弄清楚如何在 Android 中发送 post 方法 这就是我的代码的样子 public class HomeActivity extends Activity implements OnClickListener pr
  • Java中HashMap和ArrayList的区别?

    在爪哇 ArrayList and HashMap被用作集合 但我不明白我们应该在哪些情况下使用ArrayList以及使用时间HashMap 他们两者之间的主要区别是什么 您具体询问的是 ArrayList 和 HashMap 但我认为要完
  • 如何使用play框架上传多个文件?

    我在用play framework 2 1 2 使用java我正在创建视图来上传多个文件 我的代码在这里 form action routes upload up enctype gt multipart form data
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo
  • 在浏览器刷新中刷新检票面板

    我正在开发一个付费角色系统 一旦用户刷新浏览器 我就需要刷新该页面中可用的统计信息 统计信息应该从数据库中获取并显示 但现在它不能正常工作 因为在页面刷新中 java代码不会被调用 而是使用以前的数据加载缓存的页面 我尝试添加以下代码来修复
  • 在java中使用多个bufferedImage

    我正在 java 小程序中制作游戏 并且正在尝试优化我的代码以减少闪烁 我已经实现了双缓冲 因此我尝试使用另一个 BufferedImage 来存储不改变的游戏背景元素的图片 这是我的代码的相关部分 public class QuizApp

随机推荐