`

【解惑】数组向上转型的陷阱

阅读更多

问题提出:
      有两个类Manager和Employee具有继承关系 Class Manager extends Employee (setBonus是Manager特有方法)。当Manager[] 数组向上转型成Employee[] 数组的时候,很容易出现下面一个陷阱:

//创建一个Manager数组
Manager[] managers=new Manager[10];
//Ok,完全合法,因为任何managers[i]对象都是一个Manager类型,自然也是Employee类型
Employee[] employees=managers;
//Ok,完全合法,因为employees[i]声明成Employee类,完全可以引用一个Employee对象。
employees[0]=new Employee(...);
//Ok,完全合法,因为managers[i]一开始声明的时候就是Manager类型,
managers[0].setBonus(...);

     上面的程序编译器完全可以通过,但是一运行就出现了异常:java.lang.ArrayStoreException。这是为什么呢?


症结所在

      陷阱就开始于第二句: Employee[] employees=managers; 上
      这种数组的引用向上转型是十分危险,employees和managers引用的是同一个数组,employees[i]和managers[i]指向的是相同的内存区域。如果此时 employees[0]=new Employee(...);就使得managers[0]指向了一个刚创建的Employee实际对象。而managers[0]是Manager类型的。糟糕了,子类类型引用了一个父类类型对象。而且巧妙的逃过了编译器的语法检查。这样的结果导致  managers[0].setBonus(...); 看视完全合理(编译器也这么认为),但事实上 managers[0]的实际指向的对象确实Employee的,当然就没有setBonus()方法了,一运行就出异常了。

      说白了,通过将整个数组的引用向上转型,轻而易举的使得Manager m=new Employee();这句绝对错误的程序逃过了编译器的眼睛。这太让人糟糕了。

解决办法:
      作为一个程序员,运行阶段出现问题是再糟糕不过的事情了。如何避免这个让人很难发现的诡秘错误那。
      记住一条:使用数组的时候,所有的数组必须牢记创建他们元素的实际类型,并负责监督仅将类型兼容的引用存储到数组中。就如上面的:new Manager[10]创建的数组是一个经理数组。千万要避免使得Manger数组元素引用指向一个Employee类型的对象。

分享到:
评论
6 楼 javaeyebird 2009-11-05  
重复了...
5 楼 javaeyebird 2009-11-05  
patrickyao1988 写道
恩不错啊。。喊我想个让Manager m=new Employee()骗过编译器的方法,估计想不出来。。。

Object o = new Employee();
Manager m = (Manager)o;
也是编译不报错,运行报错
数组写入和这个机制一样,只是这个类型检查,虚拟机依据的是数组的实际类型,而不是声明的类型
Employee e = new Employee();
Employee[] es = new Manager[1];
es[0] = e; // 虚拟机中是 es[0] = (Manager)e
4 楼 ZavaKid 2009-11-05  
也就是说,通过数组“偷天换日”,逃过了编译器的“法眼”。
3 楼 patrickyao1988 2009-11-03  
恩不错啊。。喊我想个让Manager m=new Employee()骗过编译器的方法,估计想不出来。。。
2 楼 Heart.X.Raid 2009-11-03  
确实很基础的问题,如果你写一个句Manager m=new Employee(); 编译器绝对通过不了。但是通过数组转型,实际上就使得Manager m=new Employee(),而且编译器竟然通过了。
1 楼 GRDJE 2009-11-03  
基本语法吧

相关推荐

    C语言解惑.

    "C语言解惑"这个资源显然旨在帮助初学者扫清学习过程中的疑惑,成为他们掌握C语言的得力助手。 在C语言的学习过程中,有几个核心知识点是必须要掌握的: 1. **基本数据类型**:C语言有几种基本的数据类型,如int、...

    《C语言解惑》

    第3章到第10章分别探讨了基本数据类型的使用、控制语句、数组与指针、函数编写、自定义宏、库函数的使用、结构体和联合以及枚举类型的正确使用方法。而第11章则引入了状态机编程的基础知识,为实际编程提供更多的...

    高清版 C语言解惑—指针、数组、函数和多文件编程

    C语言解惑—指针、数组、函数和多文件编程

    行业-城投解惑系列之十二-城投转型,从建设者到运营者.rar

    行业-城投解惑系列之十二-城投转型,从建设者到运营者.rar

    java 解惑 java 解惑 java 解惑

    java 解惑 java 解惑 java 解惑 java 解惑 java 解惑 java 解惑

    java 解惑.pdf

    - **解惑**:字符数组的处理需要特别注意数组索引的使用。在循环遍历字符数组时,必须确保索引值在有效范围内。 **谜题13:畜牧场** - **描述**:涉及到字符串的拼接,结果却不符预期。 - **解惑**:字符串拼接时...

    C语言解惑中文版.pdf

    ### C语言解惑知识点概述 #### 一、文档简介 《C语言解惑》是一本旨在帮助初学者和进阶者解决C语言编程过程中遇到的各种问题的书籍。本书通过丰富的实例和深入浅出的讲解,让读者能够快速掌握C语言的核心概念和技术...

    java解惑pdf + 源代码

    例如,一个可能的谜题是关于类型转换的,它可能会涉及到向上转型和向下转型的规则,以及何时可能出现ClassCastException。通过这样的问题,读者可以了解到Java类型的静态性和安全性,以及如何正确地进行类型转换。 ...

    C语言解惑

    本书旨在帮助读者解决这些问题,通过对C语言的关键概念、语法和常见陷阱进行深入解析,使读者能够更好地掌握这门语言。以下是一些可能涵盖的重要知识点: 1. **基本数据类型**:C语言提供了包括整型、浮点型、字符...

    C语言编程技术实践 一维数组翻转课堂教学设计.docx

    - 在课堂上,采用翻转课堂模式,小组讨论并讲解知识点,教师答疑解惑,同时通过测试评估学生的学习效果。 8. **课前和课后学习任务**: - 课前预习教材和数字资源,完成自我评价测试。 - 课后进行答疑和作业,...

    Java解惑(中文版)_java_java解惑_solve65p_

    《Java解惑(中文版)》是一本专为Java初学者设计的学习资料,旨在帮助读者解答在学习Java过程中遇到的各种困惑。"solve65p"可能代表这本书包含65个问题或主题,每个都深入浅出地进行了讲解,旨在解决初学者在编程...

    C语言编程技术实践2020版 数组作为函数参数翻转课堂教学设计.docx

    教师通过设定知识问答,激发学生探究精神,同时进行答疑解惑,强化重点难点的理解。 课后学习任务则延伸到实验和作业,学生需要完成相关练习以巩固所学,如二维数组的操作,并预习实验内容,提前编写程序,以准备...

    java解惑 for all javaer

    讲述如何在程序中避免程序缺陷和程序陷阱的,解惑的过程中,介绍了一些Java编程语言中许多不易被掌握的知识点,其阅读价值非常高,适合具有Java知识的学习者和有编程经验的Java程序员阅读。

    java解惑(源代码+教程)

    Java编程语言是软件开发领域的重要组成部分,尤其在企业级应用中广泛应用。...无论你是初学者还是经验丰富的Java开发者,《Java解惑》都是一个宝贵的参考资料,可以帮助你在编程旅程中避免常见陷阱,提高代码质量。

    Java解惑 中英文

    4. **类型转换**:Java中的类型转换,包括基本类型与包装类之间的转换、向上转型和向下转型,都可能产生陷阱。书中可能通过实例解释这些转换的规则和潜在问题。 5. **集合框架**:Java集合框架是程序设计的基础,书...

    java解惑很全的题目

    在Java中,向上转型(父类引用指向子类对象)是自动的,而向下转型(子类引用指向父类对象)需要显式进行,并可能抛出`ClassCastException`。 ### 谜题 7:互换内容 互换两个变量的值通常是编程初学者会遇到的问题...

    SQL解惑 第二版(中文)pdf带目录

    《SQL解惑 第二版(中文)》是一本专门针对SQL语言疑难点进行解析的书籍,旨在帮助读者在实践中理解和掌握SQL的各种特性和技巧。这本书以其独特的案例解析方式,为学习SQL的人提供了一种生动、易懂的学习路径,避免...

Global site tag (gtag.js) - Google Analytics