赋值运算符可以分为两类:普通赋值运算符和复合赋值运算符。普通赋值运算符只能起到简单的赋值作用,而复合赋值运算符则是先完成一次其他类型的运算然后再进行赋值操作。本小节先讲述较为简单的普通赋值运算符。
2.6.1普通赋值运算符
之前在2.4小节计算圆形面积的例子当中已经使用过普通赋值运算符。普通赋值运算符的写法是“=”,其作用的是对变量进行赋值操作。赋值运算是从右向左进行的,例如:
int a = 1;
int b = 2;
a=b;//①
在语句①中,虚拟机会把“=”右边变量b的值赋给左边的变量a,而不是把“=”左边变量a的值赋给右边的变量b。
在同一条语句中,可以进行连续赋值。例如:
int a,b,c,d;
a=b=c=d=1;//②
在执行语句②时,虚拟机会首先用1给变量d赋值,从而d的值就变成了1。之后用d给c赋值,再用c给b赋值,最后用b给a赋值。
普通赋值运算符的意义和用法都很简单,但很多初学Java的读者还是会在使用这个运算符的时候出现错误,图2-10展示了使用普通赋值运算符时常见的错误:
图2-10赋值运算常见错误
通过图2-10可以看出,语句① - ⑤都出现了语法错误,下面逐条解释各语句出错的原因。语句①中,使用常量1.5给float型变量f赋值。在Java语言中,带有小数点的常量,无论其值大小,均被编译器视为double型数据。而double型数据精度高于float型,所以编译器认为把高精度数据赋值给低精度变量会导致损失精度,因此报错。但数字1.5事实上并未超出float型数据的表示范围,因此它可以在不损失精度的情况下被转换成float型数据。为了使编译器能够把数字1.5当作float型数据,需要在其后加字母f或F,这样就能顺利完成赋值,例如:
float f = 1.5F;
在程序中,如果在赋值语句中出现整数常量,编译器都会根据=左边变量的类型去看待=右边整型常量的类型。例如在语句“byte b=1;”中,编译器看到=左边的变量b是byte型,就会把=右边的常量1看作byte型。但long类型有点特殊,编译器在任何情况下都不会把一个整型常量视作long类型。在语句②中,虽然数字2200000000虽然并未超过long型数据的表示范围,但仍然出现语法错误,原因就在于编译器只能把2200000000看作int型数据,而2200000000已经超出了int型数据的最大值,因此报错。为了让编译器把2200000000当作long型数据,需要在数字后面加字母l或L,在此强烈建议读者在数字后面加大写字母L,因为小写的l与数字1非常看上去非常相似,特别容易引起混淆。因此,语句②修改为如下形式即可顺利通过编译:
long x = 2200000000L;
在语句③中,使用字符#给char型变量c赋值。但如果希望编译器把#当作字符,必须用单引号把它引起来,因此语句可以修改为:
char c = '#';
语句④之所以报错,是因为127+1的值已经超出了byte型数据的最大值,赋值会产生溢出现象,因此报错。前文在讲述算术运算导致溢出的例子中,把“2000000000+2000000000”赋值给int型变量也会出现溢出错误,但编译器并未因此报错,这是怎么回事呢?就是因为byte和short类型数据的表示范围很小,在赋值时特别容易出现溢出现象,所以编译器对这两种类型的变量做了一点“特殊照顾”,在编译代码时就检查了赋值的数据是否过大,如果过大就会直接报错,而对int型数据没有进行“特殊照顾”,因此用“2000000000+2000000000”给int型变量赋值不会“划红线”,但实际运行程序时却无法得到正确的结果。
语句⑤报错的原因也与编译器“特殊照顾”byte和short类型数据有关。在语句⑤中,s2的值为2,它的值再加上5,总和为7,数字7并未超过short型的最大值。但编译器认为s2是一个变量,只要是变量,它的值就是不固定的,也许会在某一时刻被修改为一个较大的值,而这个较大的值再加上5就有可能超出short型数据的表示范围,因此编译器不允许用“有变量出现的算术表达式”给short或byte型变量赋值,如果希望顺利完成赋值,可以把“=”右边算术表达式中的变量改为常量即可,例如:
s1 = 2 + 5;
另外,对于byte和short类型数的变量,编译器仅仅是不允许用“有变量出现的算术表达式”来为其赋值,但如果仅仅是用另一个同类型变量为其赋值仍然是可以的,也就是说“s1 = s2;”这样的操作是合法的,因为s2并不是一个“算术表达式”。
变量在被不同类型的数据赋值时,可能会遇到兼容性问题。语句①就因数据类型不兼容导致赋值操作失败。Java语言的赋值操作遵循“高大自动兼容低小”的原则。“高大”就是指精度高、占用内存空间大,而“低小”则是指精度低、占用内存空间小。如果用一个精度低、占用内存空间小的数据给一个精度高占用内存空间大的变量赋值,则可以自动完成类型转换从而实现向下兼容,例如:
int a = 1;
double b = a;
在这段代码中,int型变量a在给double型变量b赋值时,虚拟机会自动把变量a的值转换成double类型然后完成赋值操作。这个转换操作之所以能够自动完成,就是因为int型数据相对于double型变量而言,其精度较低并且占用内存空间小,在转换过程中能够保持数据“原貌”,不会损失数据精度。
相反,如果把精度高或占用内存空间大的数据赋值给精度低或占用内存空间小的变量时,就有可能会导致数据损失精度,这样的操作如同是把一块大的蛋糕放进小的盒子当中。为了能够完成这样的赋值操作,必须人为的使用“强制类型转换”方式来实现。强制类型转换的语法是:
(目标类型)数据 |
例如,把double型数据赋值给int型变量就必须使用强制类型转换的方式实现:
double a = 1.5;
int b = (int)a;
在以上赋值操作中,a的值1.5被强制转换成int型之后赋值给b。需要各位读者注意的是:1.5在被强制转换为int型数据的过程中,并不会按照四舍五入的方式进行转换,而是会把小数部分全部“砍掉”,这与两个整数做除法操作求商的运算规则是相同的。
与两种不同类型数据完成算术运算一样,赋值运算同样有可能会出现“高”与“大”冲突的现象,最典型的就是float类型变量与long型变量之间的相互赋值。long类型数据占用内存空间大但精度却低于float型数据。在这种情况下,精度较低的数据可以直接赋值给精度较高的变量,因此long类型数据可以直接赋值给float型变量。相反,float型数据给long型变量赋值时则需要强制类型转换:
float a = 1.5F;
long b = (long)a;
在实际开发过程中,程序员还可以使用赋值运算符完成对两个变量交换值的操作。如果希望通过赋值运算符交换两个变量a和b的值,需要借助一个中间变量temp。实现交换值的基本思路是:先把a的值存入temp,这相当于把a的原始值在变量temp中做了备份。然后用b给a赋值,此时a中就保存了b的值。然后用temp给b赋值,此时b中就保存了a的值,从而完成了a和b两个变量交换值的操作。交换两个变量值的完整代码如下:
【例02_05 两变量交换值】
Exam02_05.java
import java.util.Scanner;
public class Exam02_05 {
public static void main(String[] args) {
int a, b;// 要交换值的两个变量
int temp;// 中间变量
Scanner sc = new Scanner(System.in);
System.out.println("请输入变量a的值");
a = sc.nextInt();
System.out.println("请输入变量b的值");
b = sc.nextInt();
//交换变量值
temp = a;
a = b;
b = temp;
System.out.println("交换后变量a的值=" + a);
System.out.println("交换后变量b的值=" + b);
}
}
【例02-05】运行结果如图2-11所示
图2-11 【例02_05】运行结果
2.6.2复合赋值运算符
赋值运算符中除了有普通赋值运算符之外,还有复合赋值运算符。表2-4中列举了所有的复合赋值运算符。这种运算符在赋值之前都会先完成指定的运算。例如:
int a = 1;
a+=2;//①
在语句① 中,使用了“+=”这个复合赋值运算符,该语句等价于:
a = a+2;
也就是说:变量a首先与“+=”右边的2完成加法运算,然后把运算结果赋值给变量a。同理:
a*=2;
等价于:
a = a*2;
复合赋值运算符也不难理解,但初学Java的读者需要知道关于它的两条运算规则:
1.复合赋值运算符的右边会被当作整体看待
这句话的意思是:无论复合赋值运算符的右边是一个多么复杂的表达式,在执行程序的过程中,会首先对这个表达式进行计算,在得到表达式的结果之后才去进行复合赋值运算的操作,例如:
int a = 1;
a *= 3+2;//②
在语句②中,虚拟机会首先计算“*=”右边部分。“*=”的右边,表达式3+2的计算结果为5,所以语句②等价于:
a = a*5;
而如果不清楚这条运算规则,多数读者都会以“先乘除后加减”的方式来理解语句② ,误认为它应该等价于:
a = a*3 + 2;
这显然没有把复合赋值运算符的右边当作整体来看待,是一种错误典型的理解。
2.复合赋值运算符在赋值时默认带有强制类型转换效果
这句话是指:复合赋值运算符在完成赋值时会自动把运算结果强制转换成目标类型,从而使赋值操作得以顺利进行。例如:
int a = 1;
a *= 1.5;//③
以上代码中,语句③等价于:
a = a *1.5;
按照“向高大看齐”的运算规则,在进行“a*1.5”这一步运算时,整型变量a会被转换成double型,并且“a*1.5”的运算结果也是double型。而double型数据无法直接赋值给int型变量a,但语句③在IDE中并不会报错,其原因就是复合赋值运算符默认具有强制类型转换效果,因此语句③实际应该等价于:
a = (int)(a *1.5);
初学Java的读者只有深刻理解了以上两条运算规则,才算真正掌握了复合赋值运算符。
除此文字版教程外,小伙伴们还可以点击这里观看我在本站的视频课程学习Java。
标签:语句,Java,变量,int,运算符,编译器,初探,赋值 From: https://blog.51cto.com/mugexuetang/5976662