Java编程的逻辑 (3) - 基本运算
本系列文章经补充和完善,已修订整理成书《Java编程的逻辑》,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http://item.jd.com/12299018.html
运算
第一节我们谈了通过变量定义数据,上节我们介绍了给数据赋值,有了初始值之后,可以对数据进行运算。计算机之所以称为"计算"机,是因为发明它的主要目的就是运算。运算有不同的类型,不同的数据类型支持的运算也不一样,本文介绍Java中基本类型数据的主要运算。
- 算术运算:主要是日常的加减乘除
- 比较运算:主要是日常的大小比较
- 逻辑运算:针对布尔值进行运算
算术运算
算术运算符有加减乘除,符号分别是+-*/,另外还有取模运算符%,以及自增(++)和自减(--)运算符。取模运算适用于整数和字符类型,其他算术运算适用于所有数值类型和字符类型,其他都符合常识,但字符类型看上去比较奇怪,后续文章解释。
减号(-)通常用于两个数相减, 但也可以放在一个数前面,例如 -a, 这表示改变a的符号,原来的正数会变为负数,原来的负数会变为正数,这也是符合我们常识的。
取模(%)就是数学中的求余数,例如,5%3是2,10%5是0。
自增(++)和自减(--),是一种快捷方式,是对自己进行加一或减一操作。
加减乘除大部分情况和直观感觉是一样的,都很容易理解,但有一些需要注意的地方,而自增自减稍微复杂一些,下面我们解释下。
加减乘除注意事项
运算时要注意结果的范围,使用恰当的数据类型。两个正数都可以用int表示,但相乘的结果可能就会超,超出后结果会令人困惑,例如:
int a = 2147483647*2; //2147483647是int能表示的最大值
a的结果是-2。为什么是-2我们暂不解释,要避免这种情况,我们的结果类型应使用long,但只改为long也是不够的,因为运算还是默认按照int类型进行,需要将至少一个数据表示为long形式,即在后面加L或l,下面这样才会出现期望的结果:
long a = 2147483647*2L;
另外,需要注意的是,整数相除不是四舍五入,而是直接舍去小数位,例如:
double d = 10/4;
结果是2而不是2.5,如果要按小数进行运算,需要将至少一个数表示为小数形式,或者使用强制类型转化,即在数字前面加(double),表示将数字看做double类型,如下所示任意一种形式都可以:
double d = 10/4.0;
double d = 10/(double)4;
以上一些注意事项,我想也没什么特别的理由,大概是方便语言设计者实现语言吧。
小数计算结果不精确
无论是使用float还是double,进行运算时都会出现一些非常令人困惑的现象,比如:
float f = 0.1f*0.1f;
System.out.println(f);
这个结果看上去,不言而喻,应该是0.01,但实际上,屏幕输出却是0.010000001,后面多了个1。换用double看看:
double d = 0.1*0.1;
System.out.println(d);
屏幕输出0.010000000000000002,一连串的0之后多了个2,结果也不精确。
这是怎么回事?看上去这么简单的运算,计算机怎么能计算不精确呢?但事实就是这样,究其原因,我们需要理解float和double的二进制表示,后续文章进行分析。
自增(++)/自减(--)
自增/自减是对自己做加一和减一操作,但每个都有两种形式,一种是放在变量后,例如a++, a--,另一种是放在变量前,例如++a, --a。
如果只是对自己操作,这两种形式也没什么差别,区别在于还有其他操作的时候。放在变量后(a++),是先用原来的值进行其他操作,然后再对自己做修改,而放在变量前(++a),是先对自己做修改,再用修改后的值进行其他操作。例如,快捷运算和其等同的运算分别是:
快捷运算 | 等同运算 |
b=a++-1 |
b=a-1 a=a+1 |
c = ++a-1 |
a=a+1 c=a-1 |
arrA[i++]=arrB[++j] |
j=j+1 arrA[i]=arrB[j] i=i+1 |
自增/自减是"快捷"操作,是让程序员少写代码的,但遗憾的是,由于比较奇怪的语法和诡异的行为,带给了初学者一些困惑。
比较运算
比较运算就是计算两个值之间的关系,结果是一个布尔类型(boolean)的值。比较运算适用于所有数值类型和字符类型。数值类型容易理解,但字符怎么比呢?后续文章解释。
比较操作符有:大于(>),大于等于(>=),小于(<),小于等于(<=),等于(==),不等于(!=)。
大部分也都是比较直观的,需要注意的是等于。
首先,它使用两个等号==,而不是一个等号(=),为什么不用一个等号呢?因为一个等号(=)已经被占了,表示赋值操作。
另外,对于数组,==判断的是两个数组是不是同一个数组,而不是两个数组的元素内容是否一样,即使两个数组的内容是一样的,但如果是两个不同的数组,==依然会返回false,如下所示:
int[] a = new int[] {1,2,3};
int[] b = new int[] {1,2,3}; // a==b的结果是false
如果需要比较数组的内容是否一样,需要逐个比较里面存储的每个元素。
逻辑运算
逻辑运算根据数据的逻辑关系,生成一个布尔值true或者false。逻辑运算只可应用于boolean类型的数据,但比较运算的结果是布尔值,所以其他类型数据的比较结果可进行逻辑运算。
逻辑运算符具体有:
- 与(&):两个都为true才是true,只要有一个是false就是false
- 或(|):只要有一个为true就是true,都是false才是false
- 非(!):针对一个变量,true会变成false, false会变成true
- 异或(^):两个相同为false, 两个不相同为true
- 短路与(&&): 和&类似,不同之处马上解释
- 短路或 (||):与|类似,不同之处马上解释
逻辑运算的大部分都是比较直观的,需要注意的是&和&&,以及|和||的区别。如果只是进行逻辑运算,它们也都是相同的,区别在于同时有其他操作的情况下,例如:
boolean a = true;
int b = 0;
boolean flag = a | b++>0;
因为a为true,所以flag也为true,但b的结果为1,因为|后面的式子也会进行运算,即使只看a已经知道flag的结果,还是会进行后面的运算。而||则不同,如果最后一句的代码是:
boolean flag = a || b++>0;
则b的值还是0,因为||会"短路",即在看到||前面部分就可以判定结果的情况下,忽略||后面的运算。
这个例子我们还可以看出,自增/自减操作带给我们的困扰,别的操作都干干脆脆,赋值就赋值,加法就加法,比较就比较,它非混在一起,可能会少写些代码,但如果使用不当,会使理解困难很多。
运算符优先级
一个稍微复杂的运算可能会涉及多个变量,和多种运算,那哪个先算,哪个后算呢?程序语言规定了不同运算符的优先级,有的会先算,有的会后算,大部分情况下,这个优先级与我们的常识理解是相符的。
但在一些复杂情况下,我们可能会搞不明白其运算顺序。但这个我们不用太操心,可以使用括号()来表达我们想要的顺序,括号里的会先进行运算,简单的说,不确定顺序的时候,就使用括号。
小结
本节我们介绍了算术运算,比较运算和逻辑运算,但我们遗留了一些问题,比如:
- 正整数相乘的结果居然出现了负数
- 非常基本的小数运算结果居然不精确
- 字符类型怎么也可以进行算术运算和比较
这是怎么回事呢?
------------------
未完待续,查看最新文章,敬请关注微信公众号“老马说编程”(扫描下方二维码),深入浅出,老马和你一起探索Java编程及计算机技术的本质。原创文章,保留所有版权。
-----------
更多相关原创文章
计算机程序的思维逻辑 (6) - 如何从乱码中恢复 (上)?
计算机程序的思维逻辑 (7) - 如何从乱码中恢复 (下)?
Java编程的逻辑 (3) - 基本运算的更多相关文章
- 《Java编程的逻辑》 - 文章列表
<计算机程序的思维逻辑>系列文章已整理成书<Java编程的逻辑>,由机械工业出版社出版,2018年1月上市,各大网店有售,敬请关注! 京东自营链接:https://item.j ...
- Java编程的逻辑 (1) - 数据和变量
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- Java编程的逻辑 (2) - 赋值
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程的逻辑 (4) - 整数的二进制表示与位运算
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- Java编程的逻辑 (5) - 小数计算为什么会出错?
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程的逻辑 (6) - 如何从乱码中恢复 (上)?
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...
- Java编程的逻辑 (7) - 如何从乱码中恢复 (下)?
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程的逻辑 (9) - 条件执行的本质
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
- Java编程的逻辑 (10) - 强大的循环
本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...
随机推荐
- Java重写toString和泛型的使用
一.在一个类中重写toString方法 public class Person { private String name; private int age; public Person() { } ...
- Codeforces 600E Lomsat gelral(dsu on tree)
dsu on tree板子题.这个trick保证均摊O(nlogn)的复杂度,要求资瓷O(1)将一个元素插入集合,清空集合时每个元素O(1)删除.(当然log的话就变成log^2了) 具体的,每次先遍 ...
- Luogu4768 NOI2018归程(最短路径+kruskal重构树)
按海拔从大到小合并建出kruskal重构树,这样就能知道开车能到达哪些点,对这些点到1的最短路取min即可.最难的部分在于多组数据的初始化和数组大小的设置. #include<iostream& ...
- 【题解】 [POI2012]FES-Festival (差分约束)
懒得复制题面,戳我戳我 Question: (因为网上找不到好的翻译,这里简单复述一下) 告诉你\(m1+m2\)个约束条件,然后要你找出\(X_1-X_n\)这些数字,求满足要求的数列中不同的数字个 ...
- 【BZOJ1434】[ZJOI2009]染色游戏(博弈论)
[BZOJ1434][ZJOI2009]染色游戏(博弈论) 题面 BZOJ 洛谷 题解 翻硬币的游戏我似乎原来在博客里面提到过,对于这类问题,当前局面的\(SG\)函数就是所有反面朝上的硬币单一存在时 ...
- 【转】AD转换中常用的十种数字滤波法
在AD采集中经常要用到数字滤波,而不同情况下又有不同的滤波需求,下面是10种经典的软件滤波方法的程序和优缺点分析: 限幅滤波法(又称程序判断滤波法) 中位值滤波法 算术平均滤波法 递推平均滤波法(又称 ...
- maven pom 中的 build——resources 标签 mybatis加载mapper类及.xml文件
转: maven 理解 2017年12月18日 15:34:31 feicongcong 阅读数:5658 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn ...
- spring的controller默认是单例还是多例
转: spring的controller默认是单例还是多例 先看看spring的bean作用域有几种,分别有啥不同. spring bean作用域有以下5个: singleton:单例模式,当spri ...
- oracle:delete和truncate
oracle中清空表数据的两种方法 1.delete from t 2 .truncate table t 区别: 1.delete是dml操作:truncate是ddl操作,ddl隐式提交不能回滚 ...
- Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer)
Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.映射字节缓冲区 1>.什么是虚拟内存 答:虚拟内 ...