网站首页 > java教程 正文
原文
5.1.8 强制类型转换
第3章曾经讲过,将一个类型强制转换成另外一个类型的过程称为强制类型转换(casting)。Java 程序设计语言为强制类型转换提供了一种特殊的表示法。例如;
double x = 3.405;
int nx = (int) x;
将表达式 x的值转换成整数类型,舍弃了小数部分。
正像有时候需要将浮点数转换成整数一样,可能还需要将某个类的对象引用转换成另外个类的对象引用。再以混合有 Employee 和 Manager 对象的数组为例;
var staff = new Employee[3];
staff[0] = new Manager("(arl Cracker”,80000,1987,12,15);
staff[1] = new Employee("Harry Hacker",50000,1989,10,1);
staff(2] = new Employee("Tony Tester,40000,1990,3,15);
要完成对象引用的强制类型转换,转换语法与数值表达式的强制类型转换类似。用一对圆括号将目标类名括起来,并放置在需要转换的对象引用之前。例如;
Manager boss = (Manager) staff(0);
进行强制类型转换的唯一原因是:要在暂时忘记对象的实际类型之后使用对象的全部功能。例如,在ManagerTest 类中,staff 数组必须是 Eployee 对象的数组,因为它的一些元素是普通员工。我们需要将数组中引用经理的元素复原成 Manager 对象,从而能够访问它的所有新变量(需要注意,在第一节的示例代码中,为了避免强制类型转换,我们做了一些特别的处理。将 boss 变量存存入数组之前,先将它初始化为一个 Manager 对象。我需要正确的类型来设置经理的奖金)。
我们知道,在 Java 中,每个对象变量都有一个类型。类型描述了这个变量引用哪种对象以及它能做什么。例如,staff[i]引用一个 Eployee 对象(因此它还可以引用 Manager 对象)。
将一个值存入一个变量时,编译器将检查你是否承诺过多。如果将一个子类引用赋给一个超类变量,你的承诺较少,编译器是允许的。但将一个超类引用赋给一个子类变量时,就承诺过多了。必须进行强制类型转换,这样才能够通过运行时的检查。如果试图在继承链上进行向下的强制类型转换,并且“谎报”对象包含的内容,会发生什么情况呢?
Manager boss = (Manager) staff[1]; // ERROR
运行这个程序时,Java 运行时系统将注意到你的承诺不符,并产生一个 ClassCastException异常。如果没有捕获这个异常,那么程序就会终止。因此,应该养成这样一个良好的编程习惯:在进行强制类型转换之前,先查看是否能够成功地转换。为此只需要使用 instanceof 操作符。例如:
if (staff[i] instanceof Manager){
boss = (Manager) staff [ i ];
}
最后,如果这个类型转换不可能成功,那么编译器就不会让你完成这个转换。例如,下面这个强制类型转换:
String c = (String) staff[i];
将会产生编译错误,这是因为 String 不是 Employee 的子类
综上所述:
- 只能在继承层次结构内进行强制类型转换。
- 在将超类强制转换成子类之前,应该使用 instanceof 进行检查
注释:如果x为null,则进行以下测试
x instanceof C
不会产生异常,只是返回 false。这样处理是有道理的:因为 null 没有引用任何对象,当然也不会引用C类型的对象。
实际上,通过强制类型转换来转换对象的类型通常并不是一个好主意。在我们的示例中,大多数情况并不需要将 Employee 对象强制转换成 Manager 对象,两个类的对象都能够正确地调用 getSalary 方法,这是因为实现多态性的动态绑定机制能够自动地找到正确的方法。
只有在使用 Manager 中特有的方法时才需要进行强制类型转换,例如setBonus 方法。如果出于某种原因发现需要在 Employee 对象上调用 setBonus 方法,那么就应该自问超类的设计是否有问题。可能有必要重新设计超类,并添加一个setBonus 方法。请记住,一个未捕获的ClassCastException 异常就会导致程序终止。一般情况下,最好尽量少用强制类型转换和instanceof 操作符。
C++注释: Java 使用的强制类型转换语法来源于C语言“古老的过去”,但处理过程却有些像 C++的安全dynamic_cast 操作。例如,
Manager boss = (Manager) staff[i]; // Java
等价于
Manager* boss = dynamic_cast <Manager*>(staff[i]); // C++
它们之间只有一点重要的区别:当强制类型转换失败时,Java 不会生成null对象,而是抛出一个异常。从这个意义上讲,有点像 C++中的引用(reference) 转换。真是令人头疼。在 C++中,可以在一个操作中完成类型测试和类型转换。
Manager* boss = dynamic cast<Manager*>(staffi)); // C++
if (boss != NULL) ...
而在 Java 中,需要将 instanceof 操作符和强制类型转换结合起来使用:
if (staff[1] instanceof Manager)
Manager boss = (Manager) staff[i];
猜你喜欢
- 2024-11-21 Java整数和浮点数类型转换
- 2024-11-21 JavaSE基础之多态的应用场景
- 2024-11-21 第二章:Java数据类型和运算符
- 2024-11-21 int强转为byte类型么?会产生什么问题?
- 2024-11-21 Java接口&异常处理&类型转换
- 2024-11-21 详解 Java 17 中的模式匹配(Pattern Matching)
- 2024-11-21 Java基本数据类型之间的转换规则
- 2024-11-21 关于Java String 类型转换时null的问题
- 2024-11-21 [JAVA冷知识]什么是逆变与协变?数组是否支持协变&逆变?泛型呢?
- 2024-11-21 看完后让你成为武松,手把手教你打死Java中的纸老虎
你 发表评论:
欢迎- 最近发表
-
- Java内存溢出紧急处理:10个必知的Linux命令快速定位OOM
- 面试常问的 25+ 个 Linux 命令(linux面试命令大全)
- Java堆外内存溢出紧急处理实战:Linux命令定位与Spring Boot解决
- java开发常用的Linux命令,高频的没你想象的多
- Java 应用 CPU 飙升?8 个 Linux 命令组合拳快速锁定异常线程
- Java 开发者线上问题排查常用的 15 个 Linux 命令
- Java程序员必备的Linux命令:让你的工作效率翻倍
- Java程序员必备的Linux命令全解析
- [超全整理] Java 程序员必备的 100 条 Linux 命令大全
- SAP ABAP资源导航(sap aatp)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)