zoukankan      html  css  js  c++  java
  • 解读王垠博客“一道 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类型的数组,仅有一个字符串类型的数组在内存中被创建,如图:

           变量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 }
  • 相关阅读:
    微服务实战(三):深入微服务架构的进程间通信
    微服务实战(二):使用API Gateway
    微服务实战(一):微服务架构的优势与不足
    函数声明与函数表达式
    CSS样式优先级
    iframe框架及优缺点
    JS事件流模型
    JS事件冒泡及阻止
    浏览器重绘与回流
    浏览器渲染与内核
  • 原文地址:https://www.cnblogs.com/iyangyuan/p/13942674.html
Copyright © 2011-2022 走看看