(一)运算符介绍
计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量。
运算符和表达式是Java程序的基本组成要素。运算符是一种特殊的符号,用以表示数据的运算,赋值和比较。不同的运算符用来完成不同的运算。
java语言使用运算符将一个或者多个操作数连缀成执行性语句,形成表达式,表达式是由运算符和操作数按一定语法规则组成的符号序列。
以下是合法的表达式:
a + b、(a + b)*(a - b)、“name = ” + “李 明”
表达式经过运算后都会产生一个确定的值。一个常量或一个变量是最简单表达式。
(二)算数运算符
算术运算符用在数学表达式中,它们的作用和在数学中的作用一样,分为一元运算符和二元运算符,二元运算符“+”、“-”、“*”、“/”和“%”分别用来进行加、减、乘、除和取余运算。。下表列出了所有的算术运算符。
操作符 | 描述 | 例子 |
---|---|---|
+ | 加法 - 相加运算符两侧的值 | A + B 等于 30 |
- | 减法 - 左操作数减去右操作数 | A – B 等于 -10 |
* | 乘法 - 相乘操作符两侧的值 | A * B等于200 |
/ | 除法 - 左操作数除以右操作数 | B / A等于2 |
% | 取余 - 左操作数除以右操作数的余数 | B%A等于0 |
++ | 自增: 操作数的值增加1 | B++ 或 ++B 等于 21 |
-- | 自减: 操作数的值减少1 | B-- 或 --B 等于 19 |
1 + 加
System.out.println("a + b = " + (a + b) );// “+”运算符不但用于计算两个数值型数据的和,还可用于字符串对象的连接。当+运算符的两个操作数一个是字符串而另一个是其他数据类型,系统会自动将另一个操作数转换成字符串,然后再进行连接
2 - 减
减法 - 左操作数减去右操作数
3 * 乘
乘法 相乘操作符两侧的值
4 / 除法
除法运算符,除法运算符有些特殊,如果除法运算符的两个操作数都是整数类型,则计算结果也是整数,就是将自然除法的结果截断取整。如果除法运算符的两个操作数都是整数,则除数不可以是0,否则将引起除零异常。
5 % 求余运算
求余运算的结果不一定总是整数,它的结果是使用第一个操作数除以第二个操作数,得到一个整数的结果剩余的值就是余数。由于求余运算也是进行除法运算,如果除求余运算运算符的两个操作数都是整数,则求余运算的第二个操作数不可以是0,否则将引起除零异常。
在操作数涉及负数求余运算中,可通过下面规则计算:先去掉负号,再计算结果,结果的符号取被除数的符号。如求-10 % -3的结果,去掉负号求10 % 3,结果为1。由于被除数是负值,因此最终结果为-1。
大家可以自己去试一下其中一个是浮点数,或者两个都是浮点数,第二个操作数为0,或者0.0的情况。以及第一个操作数是0的情况,比较简单。
6 ++:自加运算符:
两个要点:
1 自加是单目运算符,仅仅能操作一个操作数。
除了自加自减是一元,正(+)和负(-)也是一元运算符,用来改变操作数的符号
2 自加运算符仅仅能操作一个单个数值型(整形和浮点型都可以),不能操作常量,直接量和表达式。
运算符既可以放入操作数的左边,也可以放入操作数的右边,但是表达的效果完全不一样。
// 查看 b++ 与 ++b 的不同
System.out.println("b++ = " + (b++) );
System.out.println("++b = " + (++b) );
如果把++放到左边,表示先把操作数加一,然后才把操作数放入表达式中运算。如果把++放到右边,表示先把操作数操作数放入表达式中运算,然后才把操作数加一。
7 --:自减
也是单目运算符,与++ 用法类似。
(三)赋值运算符
1 赋值运算符的定义:
赋值运算符用来为变量指定新值。
2 赋值运算符主要有两类:
一类是使用等号(=)赋值,它把一个表达式的值赋给一个变量或对 象;
另一类是扩展的赋值运算符。
3 赋值运算符的格式
variableName = expression;
这里,variableName为变量名,expression为表达式。其功能是将等号 右边表达式的值赋给左边的变量。
例如:
int x = 10;
int y = x + 20;
4 赋值运算必须是类型兼容的,即左边的变量必须能够接受右边的表达式的值,否则会产生编译错误。如下面的语句会产生编译错误。
int j = 3.14 ;
因为3.14是double型数据,不能赋给整型变量,因为可能丢失精度。编译器的错误提示是:Type mismatch:cannot convert double to int。
5 使用等号(=)可以给对象赋值,这称为引用赋值。将右边对象的引用值(地址)赋给左边的变量,这样,两个变量地址相同,即指向同一对象。如:
Date d1 = new Date();
Date d2 = d1;
此时d1、d2指向同一个对象。对象引用赋值与基本数据类型的拷贝赋值是不同的。
(四)位运算符
java支持的位运算符有7个,分为两类:位逻辑运算和移位运算。位逻辑运算符包括按位取反(~)、按位与(&)、按位或(|)和按位异或(^)4种,。移位运算符包括左移(<<)、右移(>>)和无符号右移(>>>)3种。位运算符只能用于整型数据,包括byte、short、int、long和char类型。下表列出了各种位运算符的功能与示例。假设a = 10, b = 3。
~运算符是对运算数的每一位按位取反。
下表列出了位运算符的基本运算,假设整数变量A的值为60和变量B的值为13:
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是0,则结果为0,否则为1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
(五)扩展赋值运算符
赋值运算符可以与算数运算符,位移运算符结合,扩展成为更强大的运算符。称之为扩展赋值运算符。
在赋值运算符(=)前加上其他运算符,即构成扩展赋值运算符。它的一般格式为:
variable operator = expression ;
这里operator为运算符,其含义是将变量variable 的值与expression的值做operator运算,结果赋给variable
例如,下面两行是等价的:
a + = 3 ;
a = a + 3 ;
扩展赋值运算符有11个,设a = 15, b = 3,下表给出了所有的扩展的赋值运算符及其使用方法。
只要能使用了这种扩展后的赋值运算符,通常都推荐使用它们,因为这种运算符不仅能有更好的性能,而且程序会更加健壮。
下面是Java语言支持的扩展赋值运算符:
操作符 | 描述 | 例子 |
---|---|---|
+ = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = C + A |
- = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = C - A |
* = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = C * A |
/ = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A等价于C = C / A |
(%)= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = C%A |
<< = | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
>> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
&= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
| = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
(六)关系运算符
关系运算符用来判断两个变量或者常量的大小,关系运算符的结果是一个boolean值( true或者false)。
== 检查如果两个操作数的值是否相等,即使它们是不同的数据类型,如果相等则条件为真,返回true。
在Compare这里类里测试一下。
这里提一点,如果两个操作数都是引用类型,那么只有当引用变量的类型具有父子关系的时候,才可以比较,而且这两个引用必须指向同一个对象才会返回true。
!= 如果比较的两个操作数都是数值类型,无论他们的数据类型是否相同,只要他们的值不相等,结果返回为真。
如果两个操作数都是引用类型,那么只有当引用变量的类型具有父子关系的时候,才可以比较,而且这两个引用必须指向不同对象才会返回true。
注意:基本类型的变量,值不能和引用类型的值和变量使用==进行比较。如果两个引用类型之间没有父子继承关系,那么他们的变量也不能使用== 进行比较。
> 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 (A> B)非真。
< 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 (A
>= 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。(A> = B)为假。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真A> = B)为真。
下表为Java支持的关系运算符
表格中的实例整数变量A的值为10,变量B的值为20:
运算符 | 描述 | 例子 |
---|---|---|
== | 检查如果两个操作数的值是否相等,如果相等则条件为真。 | (A == B)为假。 |
!= | 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 | (A> B)为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 | (A |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 | (A> = B)为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 | (A <= B)为真。 |
(七)逻辑运算符
逻辑运算符用于操作两个boolean类型的变量或者常量,逻辑运算符的运算对象只能是布尔型数据,并且运算结果也是布尔型数据。
逻辑运算符包括如下6种:
逻辑非(!)、逻辑与(&)、逻辑或(|)、逻辑异或(^)、短路与(&&)、短路或(||)。假设A、B是两个逻辑型数据,则逻辑运算的规则如表所示。
对一个逻辑值A,逻辑非(!)运算是当A为true时,!A的值为false,当A的值为false,!A的值为true。
对逻辑“与”(&&或&)和逻辑“或”(||或|)运算都有两个运算符,它们的区别是:“&&”和“||”为短路运算符,而“&”和“|”为非短路运算符。对短路运算符,当使用“&&”进行“与”运算时,若第一个操作数的值为false时,就可以判断整个表达式的值为false,因此,不再继续求解第二个表达式的值。
同样当使用“||”进行“或”运算时,若第一个操作数的值为true时,就可以判断整个表达式的值为true,不再继续求解第二个表达式的值。
对非短路运算符(&和|),将对运算符左右的表达式求解,最后计算整个表达式的结果。
对于逻辑异或,对运算符左右的表达式相同为flase,不同为true。
表列出了逻辑运算符的基本运算,假设布尔变量A为真,变量B为假
操作符 | 描述 | 例子 |
---|---|---|
&& | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A | | B)为真。 |
! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A && B)为真。 |
(八)三目运算符
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
表达式:
variable x = (expression) ? value if true : value if false
三目运算符的规则是,先对逻辑表达式expression进行求值,如果逻辑表达式返回true,则返回第二个操作数的值,如果逻辑表达式返回false,则返回第三个操作数值。
来举一个例子:
public class Test {
public static void main(String[] args){
int a , b;
a = 10;
// 如果 a 等于 1 成立,则设置 b 为 20,否则为 30
b = (a == 1) ? 20 : 30;
System.out.println( "Value of b is : " + b );
// 如果 a 等于 10 成立,则设置 b 为 20,否则为 30
b = (a == 10) ? 20 : 30;
System.out.println( "Value of b is : " + b );
}
}
这两种代码的写法的效果是完全相同的,三目运算符和if else 写法的区别在于:if后的代码块可以有多个语句,但三目运算符是不支持多个语句的。
(九)运算符的优先级和结合性
所有的数学运算都认为是是从左向右的,java语言中大部分运算符也是从左向右的结合的,只有单目运算符,赋值运算符合三目运算符例外,其中单目运算符,赋值运算符合三目运算符是从右向左结合,也就是从右向左运算的。
乘法和加法是两个可结合的运算,也就是说,这两个运算符左右两边的操作数可以互换位置而不会影响结果。
运算符有不同的优先级,所谓优先级就是在表达式运算中的运算顺序,下表中列出了运算符的优先级顺序,数字小的优先级总是高于数字大的优先级。
类别 | 操作符 | 关联性 |
---|---|---|
后缀 | () [] . (点操作符) | 左到右 |
一元 | + + - !〜 | 从右到左 |
乘性 | * /% | 左到右 |
加性 | + - | 左到右 |
移位 | >> >>> << | 左到右 |
关系 | >> = << = | 左到右 |
相等 | == != | 左到右 |
按位与 | & | 左到右 |
按位异或 | ^ | 左到右 |
按位或 | | | 左到右 |
逻辑与 | && | 左到右 |
逻辑或 | | | | 左到右 |
条件 | ?: | 从右到左 |
赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 |
逗号 | , | 左到右 |
根据上表中的运算符的优先级,下面分析一下 int a = 3; int b=a+2*a语句的执行过程,程序先执行2*a,得到6,在执行a+3的到9.如果使用()就可以改变程序执行的顺序,例如
int b=(a+2)*a 先执行a+2得到5 ,在执行5*a得到结果15。
无需死记硬背运算符的优先级。必要时可以在表达式中使用圆括号,圆括号的优先级最高。例如,考虑以下代码:
int x = 5;
int y = 5;
boolean z = x * 5 == y + 20;
因为“*”和“+”的优先级比“==”高,比较运算之后,z的值是true。这个表达式的可读性较差。使用圆括号修改如下:
boolean z = (x * 5) == (y + 20);
优先级大家了解一下就行。一般我们不会写非常复杂的代码,因为源代码是一份文档,可读性比运行效率更重要。
所以:不要把一个表达式写的过于复杂,若一个表达式过于复杂,则分几步来完成。
要尽量使用()来控制表达式的执行顺序,而不是过多的依赖运算符的优先级来控制表达式的执行顺序。