01_basic_07_type_conversion

第七章 类型转换与提升(Type Conversion and Promotion)

1 简介

Java是一个强类型语言(Strongly Type Language),因为每个变量在声明时必须明确给出其类型。而且,在变量的整个生命周期(Life Cycle)中,变量的类型一旦声明,不可改变,而且变量的值与其类型必须匹配。如果当变量的类型和值的类型不匹配时,程序必须进行类型转换。

为了提升开发效率,Java语言会自动为开发人员完成一些隐式类型转换(Implicit Type Conversion)。但是当Java语言无法自动完成时,就需要开发人员来处理类型转换了。我们称这种类型转换为显示类型转换(Explicit Type Conversion)

2 类型提升

类型提升(Type Promotion)是一种隐式类型转换,常常发生于基本数据类型的计算中。类型提升的原理和原因是在使用一元操作符或者二元操作符时,操作数和返回值的类型必须匹配。当其中之一不匹配时,就需要进行类型提升。类似的,在函数调用时,如果传入参数的类型和函数声明的参数类型不匹配时,也可能发生自动类型提升。

例如,在进行加法运算时,如果将一个int类型变量与一个short类型变量进行相加运算,Java程序会先将short类型的变量提升为int类型,再进行加法运算。这个类型提升过程是由Java程序自动完成的。例如,在下面的程序中,变量j会首先提升为int类型,再进行加法运算,计算k的值。因为加法操作符只能计算两个类型相同的操作数的和。

int i = 0;
short j = 1;
int k = i + j;  //先将j提升至int类型,再进行两个int类型的值的加法运算。

这样的例子还有许多。例如,下面是一个一元操作符类型提升的示例。short类型的变量i会被提升为int类型,然后再计算j的值。

short i = 1;
int j = -i;

类型提升是一个复杂的问题。类型提升的宗旨是为了将两个不兼容的操作数转换成一种通用的类型,以完成计算。在类型转换的过程中,尽量不损失计算精度。因此,在一般情况下,Java程序会将表达范围较窄的类型提升为表达范围较宽的类型。所以,当一个int类型的变量和一个双精度浮点型的变量在一起运算时,int类型的变量会被提升为双精度浮点型。

int i = 2;
double j = 9;
System.out.println("j/i is equal to " + j/i);

上述程序的打印结果为:

j/i is equal to 4.5

3 类型转换

有时隐式类型转换并不能解决所有问题。在一些场景下,开发人员不得不使用显示类型转换。显示类型转换有时又被称为强制类型转换,因为转换的类型是由开发人员强制指定的。例如,在下面的代码中,我们需要根据变量i的值来计算变量j的值。i*2的结果是int类型;当把int类型赋值给short类型时,会发生精度丢失。Java编译器会报告错误:imcompatible types: possible lossy conversion from int to short.

int i = 1;
short j = i * 2;

在这种情况下,开发人员需要使用显示类型转换,告诉编译器这不是一个错误,这是正确的计算逻辑。所以,当在代码中将计算的结果强制转换为short类型后,程序就能编译、运行了。

int i = 1;
short j = (short)(i * 2);

当然,在这里读者可能会有一个问题,我们为什么需要把变量j定义为short类型呢?如果j是int类型的变量,那么我们就不需要类型转换了。

是的,在理想情况下,具备良好设计的程序是不需要使用强制类型转换的。但是,在实际开发过程中,兼容性是一个常常出现的问题。比如,在前一环节计算得到的结果是int类型,可是在下一个环节的运算中却需要提供short类型的接口,在这种情况下,我们就得像上述的示例那样做强制类型转换了。

类似的问题还出现在Java标准库中。有时,Java标准库返回的结果是Object类型对象,开发人员必须使用强制类型转换,才能使程序正确运行。

4 类型转换分类

从上述的介绍可以看出,类型转换大致可分为向上提升或者向下转换向上提升(Widening Conversion)是指从表达能力较弱,表达范围较窄的类型提升至表达能力较强,表达范围较宽的类型。向下转换(Narrowing Conversion)则是反方向的转换;从表达能力较强,表达范围较宽的类型转换为表达能力较弱,表达范围较窄的类型。

基本数据类型的向上提升包括

  1. byte提升为short, int, long, float或者double。
  2. short提升为int, long, float或者double。
  3. char提升为int, long, float或者double。
  4. int提升为long, float或者double。
  5. long提升为float或者double。
  6. float提升为double。

基本数据类型的向下转换包括

  1. short转换为byte或者char。
  2. char转换为byte或者short。
  3. int转换为byte, short或者char。
  4. long转换为byte, short, char或者int。
  5. float转换为byte, short, char, int或者long。
  6. double转换为byte, short, char, int, long或者float。

从byte转换为char同时包含了向上提升和向下转换两种类型转换。

对象引用类型的向上提升为从子类转换为父类。从子类提升为父类是一个自然的过程,在编译过程中就能检查转换的有效性,无需任何实时类型检查。然而,对象引用的向下转换却非常复杂。转换的源类型和目标类型可以是毫无关联的两种类型。因此,Java语言会对对象引用的向下转换做运行时的检查(Runtime Type Check)。

5 小结

在Java程序设计中,开发人员难免会遇到类型不匹配的情况。为了帮助开发人员解决类型不匹配的问题,提升开发效率,Java语言提供了隐式类型转换的特性,即Java编译器会为开发人员自动的完成类型转换。但是,在某些情况下,Java编译器无能为力,需要开发人员显示的进行强制类型转换。小水滴建议开发人员应尽量避免使用强制类型转换,因为强制类型转换绕开了Java编译器的类型检查,容易在程序中埋下错误的隐患。

上一章
下一章

注册用户登陆后可留言

Copyright  2019 Little Waterdrop, LLC. All Rights Reserved.