`

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

阅读更多

问题提出:
      有两个类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 Pazzlers》Java解惑.pdf 书签齐全

    该书特写了95个有关Java或其类库的陷阱和缺陷的谜题,其中大多数谜题都采用了短...在每个谜题之后都给出了详细的解惑方案,这些解惑方案超越了对程序行为的简单解释,向读者展示了如何一劳永逸地避免底层的陷阱与缺陷。

    运营转型1.pdf

    根据提供的文档信息,我们可以归纳和总结出以下关于“运营转型”的关键知识点: ### 运营转型的概念 运营转型是指企业为了提升其核心竞争力而采取的一系列战略性调整措施,旨在优化内部流程、提升效率、降低成本,...

Global site tag (gtag.js) - Google Analytics