解读王垠博客“一道 Java 面试题”

偶然拜读IT界知名大佬王垠老师的博客,发现一个有意思的题目:

1 // 这段代码里面到底哪一行错了?为什么?
2 // 原文:http://www.yinwang.org/blog-cn/2020/02/13/java-type-system
3 public static void f() {
4     String[] a = new String[2];
5     Object[] b = a;
6     a[0] = "hi";
7     b[1] = Integer.valueOf(42);
8 }

虽然小菜才疏学浅,但本着学习交流的态度,写下此篇文章来分析一下这个问题。

首先我们要读懂每一行代码在做什么:

String[] a = new String[2];定义一个字符串类型的数组a,并初始化。

Object [] b = a; 定义一个对象类型的数组b,并将字符串类型数组a赋值给b。

a[0] = “hi”; 使用变量a访问数组中的第一个元素,赋值。

b[1] = Integer.valueOf(42); 使用变量b访问数组中的第二个元素,赋值。

只有简单的四行代码,相信读者都可以看的懂。

先不考虑太多,直接执行一下代码,编译通过,运行报错:java.lang.ArrayStoreException: java.lang.Integer。

错误提示我们第四行代码有问题,不可以将整型数据存储到数组b中,而b是一个Object类型的数组,编译通过,却无法赋值。

分析一下原因,数组b的引用指向数组a,我们操作数组b,实际在内存中,访问的应该是数组a,而数组a是一个字符串类型数组,整个过程中,并不存在Object类型的数组,仅有一个字符串类型的数组在内存中被创建,如图:

解读王垠博客“一道 Java 面试题”

变量a和变量b只不过是门面,通过这两道门,到达的是同一个房间。只不过a门只允许String类型通过,而b门没有任何限制。

因此,假如我们写下 a[0] = Integer.valueOf(42);,编译器立刻会发现错误,提示类型错误,而 b[1] = Integer.valueOf(42);的写法是 符合规则的,但由于实际数据结构是String数组,所以运行肯定无法通过。

为什么会这样?出现这种问题的根本原因,在于 Object[] b = a;,严格来说,这种语法是错误的,但是在 JDK规范中却被认可。

为什么说是错误的?面向对象中的 继承我们再熟悉不过了, 子类完全具有父类的能力,子类可以退化成为父类。

单说String的确是Object的子类,完全符合规则,但数组是另一回事,本例中String数组仅仅能容纳String类型的元素,而Object数组可以容纳任意类型的元素,String数组并非完全具有Object数组的能力。

从另一个角度看,无论是 String[] a还是 Object[] b,这两种写法中的变量a和变量b,仅仅能决定指针的指向(引用哪个具体的数组),而无法控制数组内的元素,只能整体操作,而数组必然要涉及某个元素的部分操作,这就造成数组内部数据结构的” 逸出“,必然会出现问题。

综上, 数组之间的抽象是错误的,数组之间没有直接的继承的能力,不属于面向对象继承的讨论范畴。

实际编写代码时,不必过分纠结这个问题,尽量不使用这种危险的操作,而是用更加优雅的方式去实现:

1 // 这样就能很好的发现错误,避免给自己挖坑
2 public static void f() {
3     String[] a = new String[2];
4     Object b = a;  //数组本身也是对象
5     a[0] = "hi";
6     ((String[]) b)[1] = Integer.valueOf(42);
7 }

Original: https://www.cnblogs.com/iyangyuan/p/13942674.html
Author: 杨元
Title: 解读王垠博客“一道 Java 面试题”

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/539258/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 链表——数据结构

    1.翻转链表 给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。 示例1: 输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1] 示例2:…

    Java 2023年6月7日
    090
  • 2022最新版SSM源码分析:一套教程助你深入理解底层原理,提高核心竞争力!

    众所周知SSM源码分析教程里面包括Mybatis、Spring以及SpringMVC这三个经典的开源框架的源码分析。我们编程人员技术提升逃不过的一个重要方式就是阅读和理解优秀开源项…

    Java 2023年6月9日
    099
  • Java 将HTML转为XML

    本文介绍如何通过Java后端程序代码来展示如何将html转为XML。此功能通过采用Word API- Free Spire.Doc for Java 提供的 Document.sa…

    Java 2023年5月29日
    084
  • win10,打开后任务栏下方没反应,什么都用不了,也不显示

    1、首先打开任务管理器,选择文件,选择运行新任务,输入powerShell,使用管理员进入 然后输入下面命令,完成后等一分钟即可。 Get-AppXPackage -AllUser…

    Java 2023年6月9日
    099
  • 【Android】线程池原理及Java简单实现

    线程池简介 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。 假设一个服务器完成一项任务所需时间为: T1 创建线程…

    Java 2023年5月29日
    075
  • 解决mac中wxpython对64位的支持

    今天mac 10.10.5中安装wxpython,安装完wxpython使用import wx导入模块时出现 Traceback (most recent call last): …

    Java 2023年6月8日
    049
  • 面向对象ooDay7

    .精华笔记:1)成员内部类: 应用率不高1.1)类中套类,外面的称为外部类,里面的称为内部类1.2)内部类通常只服务于外部类,对外不具备可见性1.3)内部类对象通常在外部类中创建1…

    Java 2023年6月13日
    053
  • maven添加oracle的依赖驱动

    1、下载需要的jdbc jar 包 2、下载jar包 3、在当前目录下输入cmd进入控制台 4、控制台输入 命令解释 5、执行后有如下就表示成功 6、在maven配置 1、下载需要…

    Java 2023年6月5日
    0113
  • EXCEL列乱序后内容重新对应

    excel,乱序后重排 使用公式=INDEX(D:D,MATCH(A1,C:C)).如下动图所示 还有一个好用的公式:=VLOOKUP(A1,C:D,2,FALSE)。 Origi…

    Java 2023年6月13日
    0154
  • 设计模式—组合模式

    类型:结构型 目的:将对象集合组合成 树形结构,使客户端可以以 一致的方式处理 单个对象(叶子节点)和 *组合对象(根节点) 话不多说,上优化案例。 优化案例 不使用组合模式。现有…

    Java 2023年6月7日
    0190
  • JAVA 基础(1)开发环境的搭建以及开发工具的选择

    我们现在还是在学习阶段因此我们不用配置那么多的jdk,配置一个jdk8就够应付日常的学习了。前面的文章我尽量写详细一些照顾刚入坑的朋友。后文还有教大家怎么使用企业版的idea。 一…

    Java 2023年6月13日
    077
  • docker打包Python项目成镜像文件

    做实验时因为数据太大用到了学校的服务器平台,在平台进行训练的时候首先需要搭建环境,由于种种原因,只能自己用docker来打包镜像文件,自己做镜像。记录一下遇到的坑以及解决方法。 d…

    Java 2023年6月5日
    094
  • SpringMVC(3)-RestFul风格

    一.概念:Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。 二.功能: 1.资源…

    Java 2023年6月9日
    0116
  • ThreadLocal解决了什么问题

    小明所在的项目组(迭代组:一直在迭代的路上),经常会在已有接口的基础上开发一些小功能,并且前提是在保证现有用户的不受影响基础上迭代。功能迭代,在代码层面小明有1w种实现方法(吹牛的…

    Java 2023年6月14日
    069
  • 关于博客的解读

    写在前面 大家好,这里是满满! 最近也是想来写博客,我们学习过后的知识一旦过一段时间后,自然会有一些只是会遗忘,这时候大家都会去翻看以前的视频 ,笔记,遇到难一点的问题,可能就会去…

    Java 2023年6月7日
    0105
  • windows javaee 安装

    一. 下载jdk 并安装 二. 配置环境变量 JAVA_HOME:D:\Java\jdk1.8.0_25 CLASSPATH :.;%JAVA_HOME%\lib;%JAVA_HO…

    Java 2023年5月29日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球