JAVA基础之三:运算操作符
2016-04-14 19:19
423 查看
原文链接:http://happyshome.cn/blog/java/basics/operations.html
本文中主要介绍Java中的运算操作。 如何正确的使用运算符,防止溢出是每个程序员的责任。
Java支持以下的算术运算:
对于下面的表达式:
转化为编码(1+2*a)/3 + (4*(b+c)*(5-d-e))/f - 6*(7/g+h),需要注意的不能省略乘号(*)。
优先级:
乘法(*),除法(/)和取余(%)优先于加法(+)和减法(-)运算,例如1+2*3-4/2可以表示为1+(2*3)-(4/2)。
正号(+)和负号(-)拥有更高级别。
括号()拥有最高级别,常用来调整运算顺序。
对于同级别运算符号,表达式结果从左到右计算,例如1+2-3+4等价于((1+2)-3)+4,1*2%3/4等价于((1*2)%3)/4。
算术运算仅适用于基本类型:byte, short, int, long, float, double和char,其中不包括boolean。
如果两个操作数的类型是int/long/float/double, 运算操作会直接使用此类型进行计算,例如int 5 + int 6 → int 11; double 2.1 + double 1.2 → double 3.3。
值得注意的是对于int的除法运算,计算结果会被截断,例如1/2 → 0而不是0.5。
如果两个操作数的类型是byte,short或者char,运算操作会使用int类型进行计算,char会被转化为16位无符号整数,例如byte 127 + byte 1 → int 127 + int 1 → int 128。
如果两个操作数属于不同的类型,较小的类型会被隐式的转换成较大的类型,运算操作会使用较大的类型进行计算。
举例说明:
int/double → double/double → double,1/2 → 0, 1.0/2.0 → 0.5, 1.0/2 → 0.5, 1/2.0 → 0.5。
char + float → int + float → float + float → float。
9 / 5 * 20.1 → (9 / 5) * 20.1 → 1 * 20.1 → 1.0 * 20.1 → 20.1 (你可能不会想到这个答案)。
byte 1 + byte 2 → int 1 + int 2 → int 3 (结果是int,不是byte)。
二元运算操作对于类型的转换概括如下:
如果其中一个操作数是double,另一个操作数默认转为double。
如果其中一个操作数是float,另一个操作数默认转为float。
如果其中一个操作数是long,另一个操作数默认转为long。
其余的操作数默认的转为int。
一元运算操(正号、负号)对于类型的转换概括如下:
如果操作数是double,float,long或者int,不需要转换。
其余的如果是byte,short或char,会默认转换为int。
举例说明:
取余运算符
为了计算余数会重复的运行减法运算,直到差值的绝对值小于右操作数的绝对值,举例说明:
-5 % 2 ⇒ -3 % 2 ⇒ -1
5.5 % 2.2 ⇒ 3.3 % 2.2 ⇒ 1.1
指数
在Java中是没有指数运算符的,你看到的'^'运算符是异或,不过你可以使用Math.exp(X,Y)进行指数的运算。
研究下面的代码并解释输出输出:
对于运算过程中的溢出,Java不会发出错误或者警告信息,但会产生不正确的结果。
另一方面整数除法会产生截断的整数,我们称之为向下溢出,例如1/2 → 0,而不是0.5。
做为程序员你有责任去检查编程中的溢出。
这时候我们也许会问,为什么计算机不去标记溢出?由于历史的原因, 当时处理器很慢,检查溢出会消耗性能。
在Java中,如果将double或float数据赋值给int变量会产生编译错误。
显示类型转换和类型转换
double赋值给int变量,你需要使用显示类型转换,形式为(int)value,返回的结果是被截断的int数据,举例说明:
类型转换只需要一个操作数,Java中有两种类型转换:
以(new-type)操作数的形式进行显示类型转换。
如果没有精度缺失,编译器自动的会进行隐示类型转换。
下面的这幅图展示了编译器隐示类型转换的顺序,转换规则是将小类型晋升为大类型,这样做可以防止精度缺失。降级类型需要显示类型转换,精度会缺失,值得注意的是char会被视作16位无符号整数,取值范围[0, 65535],boolean类型不支持转换。
例子,计算从1到100的平均值,仔细研究下面的代码
这是因为sum与100都是int类型,二者相除返回的是被截断的int,如果想得到正确的结果,你可以采用下面的方式:
除了前面介绍的常用的赋值运算=,Java还提供了其它的复合赋值运算:
对于一元运算自增(++)和自减(--),适用于除boolean类型以外的其它 基本类型byte, short, char, int, long, float和double。
自增和自减都是基于自身的操作,例如x++自增后重新返回给x。
自增/自减操作符号可以放置于操作数之前,也可以放在操作数之后,但是两者有着不同的意义。
如果这些运算符基于自身操作,运算符前置和后置具有同样的效果,例如++x和x++,因为表达式的值会被忽略。
如果用于其它的操作,例如y=x++或y=++x,对于y值来说运算符前置和后置有不同的值。
很多时候,你需要对两个值进行比较之后,才会进行某些操作,举例如果mark值大于等于50,输出"PASS!"。
Java提供了6种比较运算符,经过比较运算后返回布尔值即true或false。
每个比较运算符需要两个操作数,正确的写法:x > 1 && x < 100,错误的写法 1 < x < 100, 这里面&&表示与操作。
Java提供了4种基于boolean的逻辑运算,按照优先级顺序如下:
真值表如下:
举例说明:
练习:研究下面的程序并解释输出。
练习:
根据提供的日期:年、月(1-12)和日(1-31),计算该日期是否早于1582年10月15日。
运算符优先级
优先级由高到低:'!', '^','&&','||',编程中如果不确定,请使用括号()。
短路操作符
逻辑与(&&)和逻辑或(||)被称为短路操作符,这意味计算结果如果可以通过左操作数来确定,那么右操作数会被忽略,例如false && ...会返回false,true || ...会返回true。
本文中主要介绍Java中的运算操作。 如何正确的使用运算符,防止溢出是每个程序员的责任。
1. 算术运算
Java支持以下的算术运算:运算符 | 描述 | 使用 | 例子 |
---|---|---|---|
* | 乘法 | expr1 * expr2 | 2 * 3 → 6 3.3 * 1.0 → 3.3 |
/ | 除法 | expr1 / expr2 | 1 / 2 → 0 1.0 / 2.0 → 0.5 |
% | 取余 | expr1 % expr2 | 5 % 2 → 1 -5 % 2 → -1 5.5 % 2.2 → 1.1 |
+ | 加法(正号) | expr1 + expr2 +expr | 1 + 2 → 3 1.1 + 2.2 → 3.3 |
- | 减法(负号) | expr1 - expr2 -expr | 1 - 2 → -1 1.1 - 2.2 → -1.1 |
2. 算术表达式
对于下面的表达式:转化为编码(1+2*a)/3 + (4*(b+c)*(5-d-e))/f - 6*(7/g+h),需要注意的不能省略乘号(*)。
优先级:
乘法(*),除法(/)和取余(%)优先于加法(+)和减法(-)运算,例如1+2*3-4/2可以表示为1+(2*3)-(4/2)。
正号(+)和负号(-)拥有更高级别。
括号()拥有最高级别,常用来调整运算顺序。
对于同级别运算符号,表达式结果从左到右计算,例如1+2-3+4等价于((1+2)-3)+4,1*2%3/4等价于((1*2)%3)/4。
3. 混合类型运算
算术运算仅适用于基本类型:byte, short, int, long, float, double和char,其中不包括boolean。如果两个操作数的类型是int/long/float/double, 运算操作会直接使用此类型进行计算,例如int 5 + int 6 → int 11; double 2.1 + double 1.2 → double 3.3。
值得注意的是对于int的除法运算,计算结果会被截断,例如1/2 → 0而不是0.5。
如果两个操作数的类型是byte,short或者char,运算操作会使用int类型进行计算,char会被转化为16位无符号整数,例如byte 127 + byte 1 → int 127 + int 1 → int 128。
如果两个操作数属于不同的类型,较小的类型会被隐式的转换成较大的类型,运算操作会使用较大的类型进行计算。
举例说明:
int/double → double/double → double,1/2 → 0, 1.0/2.0 → 0.5, 1.0/2 → 0.5, 1/2.0 → 0.5。
char + float → int + float → float + float → float。
9 / 5 * 20.1 → (9 / 5) * 20.1 → 1 * 20.1 → 1.0 * 20.1 → 20.1 (你可能不会想到这个答案)。
byte 1 + byte 2 → int 1 + int 2 → int 3 (结果是int,不是byte)。
二元运算操作对于类型的转换概括如下:
如果其中一个操作数是double,另一个操作数默认转为double。
如果其中一个操作数是float,另一个操作数默认转为float。
如果其中一个操作数是long,另一个操作数默认转为long。
其余的操作数默认的转为int。
一元运算操(正号、负号)对于类型的转换概括如下:
如果操作数是double,float,long或者int,不需要转换。
其余的如果是byte,short或char,会默认转换为int。
举例说明:
byte b1 = 1; byte b2 = -b1; // 编译会出错, 因为-b1会返回int,不能转换成byte
取余运算符
为了计算余数会重复的运行减法运算,直到差值的绝对值小于右操作数的绝对值,举例说明:
-5 % 2 ⇒ -3 % 2 ⇒ -1
5.5 % 2.2 ⇒ 3.3 % 2.2 ⇒ 1.1
指数
在Java中是没有指数运算符的,你看到的'^'运算符是异或,不过你可以使用Math.exp(X,Y)进行指数的运算。
4. 向上溢出/向下溢出
研究下面的代码并解释输出输出:/* * "int"溢出说明 */ public class OverflowTest { public static void main(String[] args) { // int取值范围[-2147483648, 2147483647] int i1 = 2147483647; // int最大值 System.out.println(i1 + 1); // -2147483648 (溢出) System.out.println(i1 + 2); // -2147483647 System.out.println(i1 * i1); // 1 int i2 = -2147483648; // int最小值 System.out.println(i2 - 1); // 2147483647 (溢出) System.out.println(i2 - 2); // 2147483646 System.out.println(i2 * i2); // 0 } }
对于运算过程中的溢出,Java不会发出错误或者警告信息,但会产生不正确的结果。
另一方面整数除法会产生截断的整数,我们称之为向下溢出,例如1/2 → 0,而不是0.5。
做为程序员你有责任去检查编程中的溢出。
这时候我们也许会问,为什么计算机不去标记溢出?由于历史的原因, 当时处理器很慢,检查溢出会消耗性能。
5. 类型转换
在Java中,如果将double或float数据赋值给int变量会产生编译错误。double d = 3.5; int i; i = d; // 编译错误 int sum = 55.66f; // 编译错误
显示类型转换和类型转换
double赋值给int变量,你需要使用显示类型转换,形式为(int)value,返回的结果是被截断的int数据,举例说明:
double d = 3.5; int i; i = (int) d; // 将double类型的3.5转换成int类型的3,之后赋值给i
类型转换只需要一个操作数,Java中有两种类型转换:
以(new-type)操作数的形式进行显示类型转换。
如果没有精度缺失,编译器自动的会进行隐示类型转换。
int i = 3; double d; d = i; // 正确, 不需要进行类型转换,d=3.0 d = (double) i; // 也可以使用显示类型转换 double aDouble = 55; // 编译器会自动的将int 55转换成double 55.0 double nought = 0; // 编译器会自动的将int 0转换成double 0.0 // 值得注意的是int 0和double 0.0是不同的
下面的这幅图展示了编译器隐示类型转换的顺序,转换规则是将小类型晋升为大类型,这样做可以防止精度缺失。降级类型需要显示类型转换,精度会缺失,值得注意的是char会被视作16位无符号整数,取值范围[0, 65535],boolean类型不支持转换。
例子,计算从1到100的平均值,仔细研究下面的代码
public class Sum1To100 { public static void main(String[] args) { int sum = 0; double average; int number = 1; while (number <= 100) { sum += number; // sum最后的结果为int 5050 ++number; } average = sum / 100; // average = 50.0而不是50.5 System.out.println("Average is " + average); // 平均值为50.0 } }
这是因为sum与100都是int类型,二者相除返回的是被截断的int,如果想得到正确的结果,你可以采用下面的方式:
average = (double)sum / 100; // 进行除法运算前显示的将sum转成double类型 average = sum / (double)100; // 进行除法运算前显示的将100转成double类型 average = sum / 100.0; average = (double)(sum / 100); // 这种做法是错误的,你知道是什么原因吗?
6. 复合赋值运算
除了前面介绍的常用的赋值运算=,Java还提供了其它的复合赋值运算:操作符 | 解释 | 使用 | 例子 |
---|---|---|---|
= | 赋值 将右操作数赋值给左操作数 | var = expr | x = 5; |
+= | 复合加法运算 | var += expr 等价于var = var + expr | x += 5; 等价于x = x + 5 |
-= | 复合减法运算 | var -= expr 等价于var = var - expr | x -= 5; 等价于x = x - 5 |
*= | 复合乘法运算 | var *= expr 等价于var = var * expr | x *= 5; 等价于x = x * 5 |
/= | 复合除法运算 | var /= expr 等价于var = var / expr | x /= 5; 等价于x = x / 5 |
%= | 复合取余运算 | var %= expr 等价于var = var % expr | x %= 5; 等价于x = x % 5 |
7. 自增/自减
对于一元运算自增(++)和自减(--),适用于除boolean类型以外的其它 基本类型byte, short, char, int, long, float和double。操作符 | 解释 | 例子 |
---|---|---|
++ | 原数值加1 x++或++x等价于x += 1或x = x + 1 | int x = 5; x++; ++x; |
-- | 原数值减1 x--或--x等价于x -= 1或x = x - 1 | int y = 6; y--; --y; |
自增/自减操作符号可以放置于操作数之前,也可以放在操作数之后,但是两者有着不同的意义。
如果这些运算符基于自身操作,运算符前置和后置具有同样的效果,例如++x和x++,因为表达式的值会被忽略。
如果用于其它的操作,例如y=x++或y=++x,对于y值来说运算符前置和后置有不同的值。
操作符 | 解释 | 例子 |
---|---|---|
++var | 自增 首先var加1,计算结果使用var | y = ++x; 等价于x=x+1; y=x; |
var++ | 自增 首先计算结果使用var,接着var加1 | y = x++; 等价于oldX=x; x=x+1; y=oldX; |
--var | 自减 | y = --x; 等价于x=x-1; y=x; |
var-- | 自减 | y = x--; 等价于oldX=x; x=x-1; y=oldX; |
8. 关系和逻辑运算符
很多时候,你需要对两个值进行比较之后,才会进行某些操作,举例如果mark值大于等于50,输出"PASS!"。Java提供了6种比较运算符,经过比较运算后返回布尔值即true或false。
操作符 | 解释 | 使用 | 例子(x=5, y=8) |
---|---|---|---|
== | 相等 | expr1 == expr2 | (x == y) → false |
!= | 不相等 | expr1 != expr2 | (x != y) → true |
> | 大于 | expr1 > expr2 | (x > y) → false |
>= | 大于等于 | expr1 >= expr2 | (x >= 5) → true |
< | 小于 | expr1 < expr2 | (y < 8) → false |
<= | 小于等于 | expr1 >= expr2 | (y <= 8) → true |
Java提供了4种基于boolean的逻辑运算,按照优先级顺序如下:
操作符 | 解释 | 使用 |
---|---|---|
! | 逻辑非 | !booleanExpr |
^ | 逻辑异或 | booleanExpr1 ^ booleanExpr2 |
&& | 逻辑与 | booleanExpr1 && booleanExpr2 |
|| | 逻辑或 | booleanExpr1 || booleanExpr2 |
与 (&&) | true | false |
---|---|---|
true | true | false |
false | false | false |
或 (||) | true | false |
true | true | true |
false | true | false |
非 (!) | true | false |
Result | false | true |
异或 (^) | true | false |
true | false | true |
false | true | false |
// 如果x取值范围在[0,100],返回true (x >= 0) && (x <= 100) // 如果x取值范围不在[0,100],返回true (x < 0) || (x > 100) !((x >= 0) && (x <= 100)) // 计算是否为闰年:某年被4但不能被100整除,或者被400整除 ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
练习:研究下面的程序并解释输出。
public class RelationalLogicalOpTest { public static void main(String[] args) { int age = 18; double weight = 71.23; int height = 191; boolean married = false; boolean attached = false; char gender = 'm'; System.out.println(!married && !attached && (gender == 'm')); System.out.println(married && (gender == 'f')); System.out.println((height >= 180) && (weight >= 65) && (weight <= 80)); System.out.println((height >= 180) || (weight >= 90)); } }
练习:
根据提供的日期:年、月(1-12)和日(1-31),计算该日期是否早于1582年10月15日。
运算符优先级
优先级由高到低:'!', '^','&&','||',编程中如果不确定,请使用括号()。
System.out.println(true || true && false); // true (和下面的一样) System.out.println(true || (true && false)); // true System.out.println((true || true) && false); // false System.out.println(false && true ^ true); // false (和下面的一样) System.out.println(false && (true ^ true)); // false System.out.println((false && true) ^ true); // true
短路操作符
逻辑与(&&)和逻辑或(||)被称为短路操作符,这意味计算结果如果可以通过左操作数来确定,那么右操作数会被忽略,例如false && ...会返回false,true || ...会返回true。
相关文章推荐
- JAVA基础之二:变量和数据类型
- JAVA基础之一:基础语法
- SSH框架中spring的原理
- Eclipse中禁用JS验证
- 关于eclipse的快捷键
- Java反射机制深入研究
- java的动态代理机制详解 | Java基础
- Spring-bean作用域scope详解
- spring mvc+mybatis+多数据源切换
- Spring中Bean的命名 (id 和name)
- 关于加载Spring加载外部文件属性.properties的问题
- 20145325张梓靖 实验二"Java面向对象程序设计"
- NetBeans C通过gdb调试程序
- JAVA动态代理 和 Spring AOP 4种通知的简单实现
- Java语法基础---变量数据类型--类型转换
- 利用xutils框架在Android上传多个文件到Struts搭建的java服务器
- Java语法基础-变量
- 20145330《Java程序设计》第二次实验报告
- Java语法基础---进制---负数二进制
- struts获得前台数据的三种方式