第3章曾经讲过,将一个类型强制转换成另外一个类型的过程被称为类型转换。Java程序设计语言提供了一种专门用于进行类型转换的表示法。例如:

 
  
  1. double x = 3.406
  2. int nx = (int)x; 

将表达式x的值转换成整数类型,舍弃了小数部分。

    正像有时候需要将浮点型数值转换成整型数值一样,有时候也可能需要将某个类的对象引用转换成另外一个类的对象引用。对象引用的转换语法与数值表达式的类型转换类似,仅需要用一对圆括号将目标类名括起来,并放置在需要转换的对象引用之前就可以了。例如:

 
  
  1. Manager boss = (Manager)staff[0]; 

    进行类型转换的唯一原因是:在暂时忽视对象的实际类型之后,使用对象的全部功能。例如,在managerTest类中,由于某些项是普通雇员,所以staff数组必须是Employee对象的数组。我们需要将数组中引用经理的元素复原成Manager类,以便能够访问新增加的所有变量(需要注意,在前面的示例代码中,为了避免类型转换,我们做了一些特别处理,即将boss变量存入数组之前,先用Manager对象对它进行初始化。而为了设置经理的奖金,必须使用正确的类型)。

    大家知道,在Java中,每个对象变量都属于一个类型。类型描述了这个变量所引用的以及能够引用的对象类型。例如,staff[i]引用一个Employee对象(因此它还可以引用Manager对象)。

    将一个值存入变量时,编译器将检查是否允许该操作。将一个子类的引用赋给一个超类变量,编译器是允许的。但将一个超类的引用赋给一个子类的变量,必须进行类型转换,这样拆能够通过运行时的检查。

    如果试图在继承链上进行向下的类型转换,并且“谎报”有关对象包含的内容,会发生什么情况呢?

 
  
  1. Manager boss = (Manager)staff[1];    //ERROR 

    运行这个程序时,Java运行时系统将报告这个错误,并产生一个ClassCastException异常。如果没有捕获这个异常,那么程序就会终止。因此,应该养成这样一个良好的程序设计习惯:在进行类型转换之前,先查看一下是否能够成功地转换。这个过程简单地使用instanceof运算符就可以实现。例如:

 
  
  1. if(staff[1instanceof Manager) 
  2.     boss = (Manager)staff[1]; 
  3.     .... 

    最后,如果这个类型转换不可能成功,编译器就不会进行这个转换。例如,下面这个类型转换:

 
  
  1. Date c = (Date)staff[1]; 

    将会产生编译性错误,这是因为Date不是Employee的子类。

    综上所述:

  • 只能在继承层次内进行类型转换。
  • 在将超类转换成子类之前,应该使用instanceof进行检查。

    注释:如果x为null,进行下列测试

 
  
  1. instanceof C 

    不会产生异常,只是返回false。之所以这样处理时因为null没有引用任何对象,当然也不会引用C类型的对象。

    实际上,通过类型转换调整对象的类型并不是一种好的做法。在我们列举的示例中,大多数情况并不需要将Employee对象转换成Manager对象,两个类的对象都能够正确地调用getSalary方法,这是因为实现多态性的动态绑定机制能够自动地找到相应的方法。

    只有在使用Manager中特有的方法时才需要进行类型装换,例如,setBonus方法。如果鉴于某种原因,发现需要通过Employee对象调用setBonus方法,那么就应该检查一项超类的设计是否合理。重新设计一下超类,并添加setBonus方法才是正确的选择。请记住,只要没有捕获ClassCastException异常,程序就会终止执行。在一般情况下,应该尽量少用类型转换和instanceof运算符。

    C++注释:Java使用的类型转换语法来源于C语言“糟糕的旧时期”,但处理过程却有些像C++的dynamic_cast操作。例如,

 
  
  1. Manager boss = (Manager)staff[1];    //Java 

等价于

 
  
  1. Manager* boss = dynamic_cast<Manager>(staff[1]);    //C++  
  2. if(boss != NULL) 
  3.     .... 

     而在Java中,需要将instanceof运算符和类型转换组合起来使用:

 
  
  1. if(staff[1instanceof Manager) 
  2.     Manger boss = (Manger)staff[1]; 
  3.     ....