零基础学Java第2版
上QQ阅读APP看书,第一时间看更新

3.6 运算符

运算符就是在用变量或常量进行运算时,经常需要用到的符号,目前常用的总共有10种:算术运算符、关系运算符、逻辑运算符、位运算符、移位运算符、赋值运算符、三元运算符、逗号运算符、字符串运算符(将在第6章介绍)、转型运算符。下面将会对每种运算符结合实例作详细的讲述。

3.6.1 算术运算符

从小学开始就学过“加”、“减”、“乘”、“除”、“余”,其实这也是Java中的算术运算符。下面来看一种情况,当一个浮点数据加上一个整型数据,其结果是什么类型的数据?这涉及了数字精度问题,在不同类型的数据之间进行运算时,为了使结果更加精确,系统会将结果自动转化为精度更高的数据类型。

【实例3.15】以上所述的定义有点复杂,通过下面的例子进行说明。

01   ///这里的a是一个整型数据
02   ///这里的b是一个浮点型数据
03   ///相加后就是一个浮点型数据
04   public class var4
05   {
06       public static void main(String[] args)
07       {
08           int a=10;
09           float b=10f;
10           System.out.println("a+b="+(a+b));
11       }
12   }

【代码说明】第8行定义了整型变量a,第9行定义了浮点型变量b,第10行在控制台输出两个变量进行“加”运算后的结果。

【运行效果】

a+b=20.0

以上的程序代码中,变量“a”是整型,变量“b”是单精度浮点型,运算的结果是单精度浮点型。以上的实例说明了一点:为了保证经过算术运算符后结果的数据精度,尽量让结果与运算数据中精度较高的类型相同。这个例子就是让结果与“a”、“b”中精度较高的单精度浮点类型b类型相同,所以结果类型就是单精度浮点的数据类型。

如何将结果进行转换?转化有什么规律吗?笔者根据经验总结了以下几点。

❑当使用运算符把两个操作数结合到一起时,首先会将两个操作数转化成相同类型的数据。

❑两个操作数中如有一个是double型,那么另一个操作数一定先转化成double型,再进行运算。

❑两个操作数中如有一个是float型,那么另一个操作数一定先转化成float型,再进行运算。

❑两个操作数中如有一个是long型,那么另一个操作数一定先转化成long型,再进行运算。

❑其他任何两个基本类型数据操作,两个操作数都会自动转化成int型。

明白了数据精度的问题,再回到算术运算符的应用。算术运算符总共有7种:“+”、“-”、“*”、“/”、“%”(余数)、“++”(自加)、“--”(自减)。

【实例3.16】下面通过程序段来熟悉这些运算符的用法。

01   ///两个整型变量a,b通过算术运算符得出的结果
02   public class data1
03   {
04       public static void main(String[] args)
05       {
06           int a=10;
07           int b=3;
08           System.out.println("a+b="+(a+b));
09           System.out.println("a-b="+(a-b));
10           System.out.println("a*b="+(a*b));
11           System.out.println("a/b="+(a/b));
12           System.out.println("a%b="+(a%b));
13       }
14   }

【代码说明】第6~7行先定义两个整型变量,然后通过第8~12行的加、减、乘、除和求余运算,在控制台输出计算结果。

【运行效果】

a+b=13
a-b=7
a*b=30
a/b=3
a%b=1

下面重点讨论自加和自减运算符的用法,它可以使一个变量自动加1和自动减1,得到的值再赋给这个变量。

【实例3.17】自加运算符又分为两种:一种是前自加,一种是后自加。下面通过一个程序段看看什么是前自加和后自加。

01   public class data2
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(a++));
07       }
08   }

【代码说明】上面的程序段介绍了后自加,其意义就是:先把a的值赋给a,然后,将a的值加1,存储到内存空间。于是,a输出的值就是10,而存储在内存中的a的值为11。

【运行效果】

a=10

【实例3.18】再看看下面的程序段。

01   public class data3
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(++a));
07       }
08   }

【代码说明】上面的程序段演示了前自加,其意义就是:先让a的值加1,然后再将这个加之后的值赋给a。于是,a的输出值当然就是11。

【运行效果】

a=11

【实例3.19】下面来看一个综合的实例。

01   public class data4
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(a++));
07           System.out.println("a="+(++a));
08       }
09   }

【代码说明】这个程序段首先将a的值赋值给a,然后再将a加1放到内存中,内存中的值为11,那么第一个打印语句的结果就是a=10,接下来,将内存中a的值加1再赋给a,那么a的值为12。

【运行效果】

a=10
a=12

同样自减运算符也有两种:一种是前自减,一种是后自减。

【实例3.20】先看下面的程序代码。

01   public class data5
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(--a));
07       }
08   }

【代码说明】这个程序段介绍的是前自减,其意义是:先将a的值减1,然后赋值给a,于是a的结果就是9。

【运行效果】

a=9

【实例3.21】再来看看下面的程序段。

01   public class data6
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(a--));
07       }
08   }

【代码说明】这个程序段介绍的是后自减,其意义是:将a的值赋给a后,再将a的值自动减1,于是输出a是10。

【运行效果】

a=10

【实例3.22】下面再看一个综合实例。

01   public class data7
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(a--));
07           System.out.println("a="+(--a));
08       }
09   }

【代码说明】这个程序段首先将a的值赋值给a,然后再将a减1放到内存中,内存中的值为9。那么第一个打印语句的结果就是a=10。接下来,将内存中a的值减1再赋给a,那么a的值为8。

【运行效果】

a=10
a=8

【实例3.23】在现实的编程中,可能会遇到更加复杂的代码段。下面继续看一个综合的实例。

01   public class data8
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           System.out.println("a="+(a--));
07           System.out.println("a="+(--a));
08           System.out.println("a="+(a++));
09           System.out.println("a="+(++a));
10       }
11   }

【代码说明】首先将a的值赋给a,然后将a自动减1放到内存中,此时内存中值为9,所以第一个打印语句输出的值为10。接着,将内存的值先减1再赋给a,a就为8。随后,将a的值先赋给a,再将a的值加1放到内存中,所以内存中a为9。最后将内存中的值加1再赋给a,a的值为10。

【运行效果】

a=10
a=8
a=8
a=10

为了能方便地记忆自加和自减运算符的用法,总结如下:

❑++x:因为++在前,所以可以记忆为先加后用。

❑x++:因为++在后,所以可以记忆为先用后加。

❑ --x:因为--在前,所以可以记忆为先减后用。

❑x--:因为--在后,所以可以记忆为先用后减。

3.6.2 关系运算符

关系运算符就是指两个操作数之间的关系,它包括“>”、“<”、“>=”、“<=”、“==”、“!=”。算术运算符的结果都是数字,而关系运算符的结果则是布尔型数据,这一点一定要注意。

在实际开发中,经常使用关系运算符来作为判断的条件,如果条件是真,将如何处理,如果条件是假,又该如何处理。

【实例3.24】下面看一个简单的例子,看看关系运算符的输出是什么样子。

01   ///关系运算符的应用
02   public class data9
03   {
04       public static void main(String[] args)
05       {
06           int a=10;
07           int b=21;
08           System.out.println("说a>b,对吗?"+(a>b));
09           System.out.println("说a>=b,对吗?"+(a>=b));
10           System.out.println("说a<b,对吗?"+(a<b));
11           System.out.println("说a<=b,对吗?"+(a<=b));
12           System.out.println("说a==b,对吗?"+(a==b));
13           System.out.println("说a!=b,对吗?"+(a!=b));
14       }
15   }

【代码说明】第6~7行首先定义了两个变量a和b,第8~13行通过比较两个变量的大小,来输出关系运算的结果。

【运行效果】

说a>b,对吗?false
说a>=b,对吗?false
说a<b,对吗?true
说a<=b,对吗?true
说a==b,对吗?false
说a!=b,对吗?true

说明

从以上的程序段可以看出,关系运算符的结果是布尔型数据。

3.6.3 逻辑运算符

逻辑运算符共有3种:“非”、“与”、“或”。逻辑运算符一般与关系运算符结合起来使用,下面将详细地介绍这3个逻辑运算符。

1. NOT运算符

NOT运算符就是一个否定的意思,因为英文中“NOT”就是“不”的意思,在Java中,NOT用符号“!”表示。

【实例3.25】下面看一个简单的例子。

01   ///非逻辑运算符的应用
02   public class data10
03   {
04       public static void main(String[] args)
05       {
06           int a=10;
07           int b=21;
08           System.out.println("说a>b,对吗?"+!(a>b));
09       }
10   }

【代码说明】在程序中,“a>b”是假的,即“false”,但是前面有个“!”否定运算符,将“false”变成了“true”。

【运行效果】

说a>b,对吗?true

2. AND运算符

根据英文“AND”的意思,就知道此运算符是“与”的意思。使用它必须要满足AND前后两个条件。AND运算符在Java中用符号“&&”表示。

【实例3.26】下面看一个简单的实例。

01   ///与逻辑运算符的应用
02   public class data11
03   {
04       public static void main(String[] args)
05       {
06           int a=10;
07           int b=21;
08           System.out.println("认为既a>b又a<b,对吗?"+((a>b)&&(a<b)));
09       }
10   }

【代码说明】“a<b”这个关系运算得出的结果是“true”,而“a>b”这个关系运算得出的结果是“false”。两者用AND这个逻辑运算符连接后,得出的结果是“false”。

【运行效果】

认为既a>b又a<b,对吗?false

为什么会这样呢?下面是AND运算符的原理:

两个操作数只要有一个是“false”,那么结果就是“false”,如果两个操作数都是“true”,那么结果才是“true”。

3. OR运算符

根据英文“OR”的意思,就知道此运算符是“或”的意思,使用它只要满足“OR”前后两个条件中任意一个条件。OR运算符在Java中用符号“||”表示,其原理如下:

两个操作数只要有一个是“true”,那么结果就是“true”,否则结果就是“false”。

【实例3.27】下面看一个简单的例子。

01   public class data12
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           int b=21;
07           int c=10;
08           System.out.println("认为既a>b又a<b,对吗?"+((a>=b)||(a==b)));
09           System.out.println("认为既a>b又a=c,对吗?"+((a<b)||(a==c)));
10       }
11   }

【代码说明】上面的程序段中,“a>=b”和“a==b”两个操作数的结果都是“false”,所以或的结果就是“false”,而“a<b”的结果是“true”,“a==c”的结果是“true”,所以结果就是“true”。

【运行效果】

认为既a>b又a<b,对吗?false
认为既a>b又a=c,对吗?true

逻辑运算符主要用于判断条件,例如后面要讲述的判断语句、循环语句的条件判断等。

3.6.4 位运算符

位运算符主要针对二进制进行运算,它包括“与”、“非”、“或”、“异或”。从表面上看似乎有点像逻辑运算符,但逻辑运算符是针对两个关系运算符来进行逻辑运算,而位运算符主要针对两个二进制数的位进行运算。下面详细介绍每个位运算符。

1. 与运算符

与运算符用符号“&”表示,其使用规律如下:

【实例3.28】两个操作数中位都为1的情况下,结果才为1,否则结果为0,例如下面的程序段。

01   public class data13
02   {
03       public static void main(String[] args)
04       {
05           int a=129;
06           int b=128;
07           System.out.println("a和b与的结果是:"+(a&b));
08       }
09   }

【代码说明】“a”的值是129,转换成二进制就是10000001,而“b”的值是128,转换成二进制就是10000000。根据与运算符的运算规律,只有两个位都是1,结果才是1,可以知道上述结果就是10000000,即128。

【运行效果】

a和b与的结果是:128

2. 或运算符

或运算符用符号“|”表示,其运算规律如下:

两个位只要有一个为1,那么结果就是1,否则就为0。

【实例3.29】下面看一个简单的例子。

01   public class data14
02   {
03       public static void main(String[] args)
04       {
05           int a=129;
06           int b=128;
07           System.out.println("a和b或的结果是:"+(a|b));
08       }
09   }

【代码说明】a的值是129,转换成二进制就是10000001,而b的值是128,转换成二进制就是10000000,根据或运算符的运算规律,两个位中有一个是1,结果就是1,可以知道上述结果就是10000001,即129。

【运行效果】

a和b或的结果是:129

3. 非运算符

非运算符用符号“~”表示,其运算规律如下:

如果位为0,结果是1;如果位为1,结果是0。

【实例3.30】下面看一个简单的例子。

01   public class data15
02   {
03       public static void main(String[] args)
04       {
05           int a=2;
06           System.out.println("a非的结果是:"+(~a));
07       }
08   }

【代码说明】a的值是2,转换成二进制就是0010,因为非运算就是取相反的位值,而且取反是针对二进制的所有位置而言,因为二进制中最高位是1表示负数,所以最终转换为十进制就是-3。

注意

本章中所计算的一些二进制,写作方法都没有那么复杂,如int类型占4字节,每个字节是8位,则对于数值2来说,标准的二进制应该是00000000 00000000 00000000 00000010,一共是32位。但为了简化说法,我们并不把多余的给出来。上述二进制进行非运算后是11111111 11111111 11111111 11111101。如果计算机基础学得好的读者,可能还会知道负数的二进制,其实是它绝对值的二进制取反再加1。上述非运算后的结果是00000000 00000000 00000000 00000011这个二进制取反加1的结果,而这个值转换为十进制就是3,因为最高位是1表示负数,所以结果为-3。如果读者还不明白此内容,可以参考一些数据结构和汇编语言的专业书籍。

【运行效果】

a非的结果是:-3

4. 异或运算符

异或运算符是用符号“^”表示的,其运算规律是:

两个操作数的位中,相同则结果为0,不同则结果为1。

【实例3.31】下面看一个简单的例子。

01   public class data16
02   {
03       public static void main(String[] args)
04       {
05           int a=15;
06           int b=2;
07           System.out.println("a与 b异或的结果是:"+(a^b));
08       }
09   }

【代码说明】a的值是15,转换成二进制为1111,而b的值是2,转换成二进制为0010,根据异或的运算规律,可以得出其结果为1101,即13。

【运行效果】

a与b异或的结果是:13

3.6.5 移位运算符

移位运算符也针对二进制的“位”,它主要包括左移位运算符(<<)、右移位运算符(>>>)、带符号的右移位运算符(>>)。

1. 左移运算符

左移运算符用“<<”表示,是将运算符左边的对象,向左移动运算符右边指定的位数,并且在低位补0。

【实例3.32】其实,向左移n位,就相当于乘上2的n次方,例如下面的例子。

01   public class data17
02   {
03       public static void main(String[] args)
04       {
05       int a=2;
06       int b=2;
07       System.out.println("a移位的结果是:"+(a<<b));
08       }
09   }

【代码说明】首先从本质上来分析,2的二进制是00000010,它向左移动2位,就变成了00001000,即8。如果从另一个角度来分析,它向左移动2位,其实就是乘上2的2次方,结果还是8。

【运行效果】

a移位的结果是:8

2. 右移运算符

【实例3.33】右移运算符用符号“>>>”表示,是将运算符左边的对象向右移动运算符右边指定的位数,并且在高位补0,其实右移n位,就相当于除上2的n次方。

01   public class data18
02   {
03       public static void main(String[] args)
04       {
05           int a=16;
06           int b=2;
07           System.out.println("a移位的结果是:"+(a>>>b));
08       }
09   }

【代码说明】从本质上来分析,16的二进制是00010000,它向右移动2位,就变成了00000100,即4。如果从另一个角度来分析,它向右移动2位,其实就是除以2的2次方,结果还是4。

【运行效果】

a移位的结果是:4

3. 带符号的右移运算符

带符号的右移运算符用符号“>>”表示,是将运算符左边的运算对象,向右移动运算符右边指定的位数。

【实例3.34】如果是正数,在高位补零,如果是负数,则在高位补1,先看下面一个简单的例子。

01   public class data19
02   {
03       public static void main(String[] args)
04       {
05           int a=16;
06           int c=-16;
07           int b=2;
08           int d=2;
09           System.out.println("a的移位结果:"+(a>>b));
10           System.out.println("c的移位结果:"+(c>>d));
11       }
12   }

【代码说明】a的值是16,转换成二进制是00010000,让它右移两位成00000100即4。c的值是-16,转换成二进制是11101111,让它右移一位是11111011即-4。

【运行效果】

a的移位结果:4
c的移位结果:-4

3.6.6 赋值运算符

赋值就是将数值赋给变量,而这个赋值运算符就充当了这个赋值的任务,其实最简单的赋值运算符就是“=”。

当然除了“=”外,还有很多其他的赋值运算符。有“+=”、“-=”、“*=”、“/=”、“%=”、“>>=”、“>>>=”、“<<=”、“&=”、“|=”、“^=”。

【实例3.35】下面给出一个简单的例子。

01   public class data20
02   {
03       public static void main(String[] args)
04       {
05            int a=5;
06            int b=2;
07            System.out.println("a+=b的值:"+(a+=b));
08            System.out.println("a-=b的值:"+(a-=b));
09            System.out.println("a*=b的值:"+(a*=b));
10            System.out.println("a/=b的值:"+(a/=b));
11            System.out.println("a%=b的值:"+(a%=b));
12            System.out.println("a>>=b的值:"+(a>>=b));
13            System.out.println("a>>>=b的值:"+(a>>>=b));
14            System.out.println("a<<=b的值:"+(a<<=b));
15            System.out.println("a&=b的值:"+(a&=b));
16            System.out.println("a|=b的值:"+(a|=b));
17            System.out.println("a^=b的值:"+(a^=b));
18       }
19   }

【代码说明】第7行的“a+=b”就是a=a+b。第8行的“a-=b”就是a=a-b。第17行的“a^=b”就是a=a^b。

【运行效果】

a+=b的值:7
a-=b的值:5
a*=b的值:10
a/=b的值:5
a%=b的值:1
a>>=b的值:0
a>>>=b的值:0
a<<=b的值:0
a&=b的值:0
a|=b的值:2
a^=b的值:0

3.6.7 三元运算符

三元运算符一般用得很少,因为它在程序段中的可读性很差,所以笔者建议不要经常使用三元运算符,但很少使用并不代表不使用,所以还是要掌握好它的用法。三元运算符的表达形式如下:

布尔表达式?值0:值1

它的运算过程是:如果布尔表达式的结果是true,就返回值0;如果布尔表达式的结果是false,就返回值1。

【实例3.36】例如下面的程序段。

01   public class data21
02   {
03       public static void main(String[] args)
04       {
05           int a=10;
06           int b=20;
07           System.out.println("此三元运算式结果是:"+((a>b)?'A':'B'));
08       }
09   }

【代码说明】因为“a”小于“b”,所以“a>b”这个关系运算符的结果是“false”,既然是“false”,那么选择值1,即这个三元运算符的结果是“B”。

【运行效果】

此三元运算式结果是:B

3.6.8 逗号运算符

在Java程序设计中,逗号运算符一般是用来将几个数值彼此分开,例如数组中的每个元素都是使用逗号与其他元素分开的。这个运算符太简单了,这里不再给出实例。

3.6.9 转型运算符

转型运算符的用处是将一种类型的对象或数据,经过强制转换而转变为另一种类型的数据。它的格式是在需要转型的数据前加上“()”,然后在括号内加入需要转化的数据类型。

【实例3.37】有的数据经过转型运算后,精度会丢失,而有的会更加精确,下面的例子可以说明这个问题。

01   public class data22
02   {
03       public static void main(String[] args)
04       {
05            int x;
06            double y;
07            x=(int)34.56+(int)11.2;
08            y=(double)x+(double)10;
09            System.out.println("x="+x);
10            System.out.println("y="+y);
11       }
12   }

【代码说明】第7行中,由于在34.56前有一个int的强制类型转化,所以34.56就变成了34。同样,11.2就变成了11,所以x的结果就是45。第8行中,在x前有一个double类型的强制转换,所以x的值变为45.0,而数值11也被强制成double类型,变成11.0,所以最后y的值变为56.0。

【运行效果】

x=45
y=56.0

3.6.10 运算符的优先级别

当多个运算符出现在一个表达式中,谁先谁后呢?这就涉及运算符的优先级别。在一个多运算符的表达式中,运算符优先级不同会导致最后得出的结果差别甚大,例如,(1+3)+(3+2)*2,这个表达式如果按加号最优先计算,答案是18,如果按照乘号最优先,答案则是14。

下面将详细介绍在Java程序设计中,各个运算符的优先级别,如表3.1所示。

表3.1 运算符优先级表