Java操作符真的简单到易如反掌?
之前我写了一篇《吃人的那些Java名词:对象、引用、堆、栈和堆栈》,本以为凭借自己8年的Java编程经验足够把这些“吃人”的Java名词解释清楚了,但有网友不以为然,在文章底部评论说:“老哥,你真的有8年java开发经验么。。。”(告诉我,为什么要用三个句号。。。而不是三个问号???)鉴于此,我在写这篇《Java操作符真的简单到易如反掌?》时感到惶恐不安,头顶三个大字几乎压得我喘不过气来,哪三个字呢?
——“臣有罪”,外加三个感叹号!!!。
但转念想到北航出版社董老师给我的建议:
你面对的是编程爱好者,或初级技术人员;所以不要担心,你把步骤写清楚,给人一种手把手的感觉,以实践和实例为主,技术原理为辅;让读者从简单开始,引导读者自己往深入的地方钻研。这样的话,你写作的目的也就达成了。
我惴惴不安的心情也就渐渐释然了——别担心那些抵触的声音,写好自己的文章就对了。
一、“=”号的宣言:我不是判官,我只是用来赋值的
记得10年刚参加工作的时候,我的同事小王就因为一行简单的代码被领导骂的狗血喷头。当时小王被骂的那个惨啊,至今我还历历在目。究竟是一行什么代码呢?据我惨痛的回忆,大概是这样的:
if (b = c) { // ... }
我那同事小王很明显是想要判断b和c是否相等(==),然而却莫名其妙的少了一个=号,变成了赋值操作;我相信小王绝对不是故意的,只是当时急于和女朋友聊天少写了一个=号而已。但这样的错误竟然没有被编译器发现,因为当b和c是布尔(boolean)类型时,编译器就不会报错提示——这真是小之又小的概率,就这么不幸的被小王撞上了(重要的是被领导当众羞辱)——从此以后,小王对编程失去了信心,实习期没结束,小王就转行做汽车销售了。
悲哀啊!
我和小王相处的时间大概有3个月吧,对他的印象蛮好的,蛮聪明伶俐的一个少年;可惜被这样一个不经意的错误给耽搁了。
是时候给“=”号一个明确的宣言了:我不是判官,我只是用来赋值的;什么意思呢?意思是,取“=”号右边的值(右值),把它复制给左边(左值);右值可以是任何常数、变量或者生成一个值得表达式;但左值必须是一个明确的、已命名的变量。例如,可以将一个字符串赋值给一个变量:
String cmower = "沉默王二,一个不止写程序的全栈工程师";
关键点:
1)得到你的人却得不到你的心;来看这么一段代码:
int i = 520, j = 521; // 此时的i和j非常恩爱 System.out.println("i=" + i + ",j=" + j); // 输出:i=520,j=521 // 就当他俩结婚了 i = j; // 然而i却疯了 i = 250; // 但j却不为所动 System.out.println("i=" + i + ",j=" + j); // 输出:i=250,j=521
怎么解释上面这段代码呢?答案是:
基本数据类型在赋值(生动而又不恰当的说法就是结婚吧)的时候,其实是把右值复制给了左值;但在左值发生改变的时候,右值却不会改变。这样的说法其实很绕,简单点的说法是基本类型的赋值是不会相互影响的,和对象引用的赋值是完全不同的;对象引用的赋值是会相互影响的。
2)你若不爱,我便不爱;来看这么一段代码:
class Lover { int level; } public class OperationalCharacter { public static void main(String[] args) { testTrueLove(); } public static void testTrueLove() { Lover boy = new Lover(); boy.level = 520; Lover girl = new Lover(); girl.level = 521; // 此时的男孩和女孩非常恩爱 System.out.println("boy.level=" + boy.level + ",girl.level=" + girl.level); // boy.level=520,girl.level=521 // 就当他俩结婚了 boy = girl; // 女孩不爱了 girl.level = 582; // 男孩也不爱了 System.out.println("boy.level=" + boy.level + ",girl.level=" + girl.level); // boy.level=582,girl.level=582 } }
怎么解释上面这段代码呢?答案是:
对象引用在赋值的时候,其实改变的是引用的地址;boy = girl;
使boy也指向了girl的那个地址。因此,当girl.level改变的时候,boy.level也发生了变化。
3)有钱之后还能保持自我吗?来看这么一段代码:
class Money { int coin; } public class OperationalCharacter { public static void main(String[] args) { // 穷光蛋a int a = 0; // 穷光蛋b Money b = new Money(); b.coin = 0; testQuality(a, b); System.out.println("a=" + a + ",b.coin=" + b.coin); // 输出:a=0,b.coin=10000000 } public static void testQuality(int a, Money b) { // 有钱了 a = 10000000; b.coin = 10000000; } }
怎么解释上面这段代码呢?答案是:
基本数据类型作为参数传递给方法之后,尽管在方法中发生了改变,但跳出方法之后的值并不会发生变化;就像a同学,在传递给testQuality方法前是个穷光蛋,尽管在testQuality方法中变成了千万富翁,但跳出testQuality方法后依然是个穷光蛋。
对象引用作为参数传递给方法之后,一旦在方法中发生了改变,跳出方法之后的值也会发生变化;就像b同学,在传递给testQuality方法前是个穷光蛋,在testQuality方法中变成了千万富翁,那么跳出testQuality方法后仍然是个千万富翁。
话外音:如果你把这种情形归结为命,我是认同的。
二、double的宣言:注意精度哦!
Java的基本算术操作符包括加号(+)、减号(-)、除号(/)、乘号(*)和取余(%);它们的使用方法就好像吃一口苹果那样简单,所以不再赘述。但需要注意一点,就是精度问题,来看这样一个示例:
double m = 6; double n = 6.4; double o = m * n; System.out.println("m=" + m + ",n=" + n + ",o=" + o); // 输出:m=6.0,n=6.4,o=38.400000000000006
你猜想o的输出结果肯定是38.4,因为m是6,n是6.4,它们的乘积自然是38.4啊!但你这样的猜想就好像买了一注大乐透;根据你设定的公式,这一注大乐透中一百万都是小的;但结果是,你又成功贡献了一次奖金池。为什么o的结果是38.400000000000006?为什么会这样?究竟为什么?
答案:首先,计算机进行的是二进制运算,我们输入的十进制数字会先转换成二进制,进行运算后再转换为十进制输出。double提供了快速的运算,然而问题在于转换为二进制的时候,有些数字不能完全转换,只能无限接近于原本的值,这就导致了在后来的运算会出现不正确结果的情况。
剧透:不止是double会有精度问题,float也会有精度问题。
那么,精度问题该怎么解决呢?
BigDecimal !!!
涉及到小数运算时一定要使用BigDecimal !!!
不要使用double和float。
来看一下解决方案的代码:
BigDecimal m1 = BigDecimal.valueOf(6); BigDecimal n1 = BigDecimal.valueOf(6.4); BigDecimal o1 = m1.multiply(n1); System.out.println("m1=" + m1 + ",n1=" + n1 + ",o1=" + o1); // 输出:m1=6,n1=6.4,o1=38.4
有人说,为什么要用BigDecimal.valueOf()
而不用new BigDecimal()
?答案如下:
BigDecimal m2 = new BigDecimal(6); BigDecimal n2 = new BigDecimal(6.4); BigDecimal o2 = m2.multiply(n2); System.out.println("m2=" + m2 + ",n2=" + n2 + ",o2=" + o2); // 输出:m2=6,n2=6.4000000000000003552713678800500929355621337890625,o2=38.4000000000000021316282072803005576133728027343750
讲究,特别的讲究。
三、害死人的自动递增,不偿命的自动递减
记得参加工作的第二年,我的同事小二就因为把“前缀递增”写成了“后缀递增”被一顿痛骂之后拉出去祭天了。至今我还耿耿于怀,因为我也是参与者之一(当时小王准备使用p = p + 1
,但我劝小王使用p++
,因为自动递增更加简洁);但小二很讲义气,没有把我捅出去,我才苟且活到今日。往事不堪回首,但为了以后的Java程序员着想,我决定忍着记忆的苦涩把小二当年的那段代码记录下来:
public static void main(String[] args) { int p = 0; calculate(p); } public static void calculate(int p) { if (p < 3) { // 其他 calculate(p++); } }
按照以上的代码来看,这是一个死循环,calculate迭代是不会跳出的,直到程序报错。为什么会这样呢?
因为后缀递增会先生成值,再执行运算;也就是p++这个表达式的结果还是p。但前缀递增会先执行运算,再生成值;也就是++p这个表达式的结果是p+1。
那以上代码正确的写法是什么呢?答案如下:
public static void main(String[] args) { int p = 0; calculate(p); } public static void calculate(int p) { if (p < 3) { // 其他 calculate(++p); } }
四、我俩到底等不等?
==
用来判断操作符两侧的值是否相等——老生常谈的话题了;凡是遇到字符串比较,请使用equals()方法,这个大家都已经心知肚明了,不需要再强调;但对于Integer类型的值进行比较时,还需要特别强调一下;因为针对实际的项目来说,遇到数据库中字段类型为int时,Java对象与之对应的属性需要声明是Integer(注意,不是int),Integer在比较是否相等时不能使用==
!为什么呢?请看以下代码:
Integer q = 127; Integer r = 127; System.out.println(q == r); // true q = 128; r = 128; System.out.println(q == r); // false
为什么一个是true,一个是false?
因为Integer作为常量时,对于-128到127范围之间的数,Java会对其进行缓存;也就是说Integer q = 127
时,Java会将其存放在缓存中,当执行Integer r = 127
时,Java发现缓存中存在127这个数了,就直接取出来赋值给r,所以此时的q == r,也就是说System.out.println(q == r)
此时输出true。当q和r不在-128到127之间的范围时,Java会通过new Integer()来创建该数值,所以q和r被赋值为128时q != r,也就是说System.out.println(q == r)
此时输出false。
针对这个情况,在判断Integer是否相等时,尽量使用以下代码来进行判断:
System.out.println(q.intValue() == r.intValue()); System.out.println(q.compareTo(r) == 0);
注意:前提条件是q和r都不为null。
五、跳过的位移运算符
对不起,我选择跳过!
六、特别的三元操作符
来看这样一段代码:
boolean flag = true; System.out.println(flag ? "点赞转发分享" : "踩死你丫的");
三元操作符也称为条件操作符,它很简洁,也很特别,因为它有三个操作数:
boolean-exp ? value0 : value1
?前面是布尔表达式,?后面是两个可选值(用:隔开),布尔表达式为true,则三元操作符的结果是value0,否则是value1。
Java操作符真的简单到易如反掌?的更多相关文章
- JavaSE复习日记 : Java操作符\关系运算符\逻辑运算符\赋值运算符\字符串连接符\三元运算符
// Java操作符\关系运算符\逻辑运算符\赋值运算符\字符串连接符\三元运算符 /* * 一 Java操作符 * * Java操作符都有哪些? * +, -, *, /, %, ++, -- * ...
- java入门---简介&简单输出小例子&开发前准备
Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言和Java平台的总称.由James Gosling和同事们共同研发,并在1995年正式推出.J ...
- Java中真的只有值传递么?
Java中真的只有值传递么? (本文非引战或diss,只是说出自己的理解,欢迎摆正心态观看或探讨) 回顾值传递和引用传递 关于Java是值传递还是引用传递,网上有不一样的说法. 1.基本类型或基本类型 ...
- Java操作符
几乎所有运算符都只能操作"主类型"(Primitives).例外是"="."= ="和"! =",它们能操作所有对象.除 ...
- Java 异步处理简单实践
Java 异步处理简单实践 http://www.cnblogs.com/fangfan/p/4047932.html 同步与异步 通常同步意味着一个任务的某个处理过程会对多个线程在用串行化处理,而异 ...
- 使用Java编写一个简单的Web的监控系统cpu利用率,cpu温度,总内存大小
原文:http://www.jb51.net/article/75002.htm 这篇文章主要介绍了使用Java编写一个简单的Web的监控系统的例子,并且将重要信息转为XML通过网页前端显示,非常之实 ...
- Java中的简单工厂模式
举两个例子以快速明白Java中的简单 工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面.女娲造人,这就 ...
- Java之英格玛简单实现以及加密验证码的应用
最近看了一部电影<模仿游戏>,<模仿游戏>中艾伦·图灵破译英格玛让我对英格玛产生了好奇,于是就开始翻阅资料对其进行研究,但是毕竟智慧有限,所以我这里用Java实现一个简单的英格 ...
- java性能真的差吗
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt275 我见过java运行在手机上,包括很廉价的山寨手机,但是却暂时没发现.n ...
随机推荐
- python全栈开发day113-DBUtils(pymysql数据连接池)、Request管理上下文分析
1.DBUtils(pymysql数据连接池) import pymysql from DBUtils.PooledDB import PooledDB POOL = PooledDB( creato ...
- java-数组排序--冒泡排序、鸡尾酒排序、地精排序
冒泡排序 冒泡排序的思想是,让依次数组中相邻的数进行比较,如果前一个数比后一个数大,则两数进行交换,大的数就会象泡泡一样慢慢浮在水面上了 见图解 稳定性:稳定时间复杂度:O(n2) public st ...
- .net core 上传文件大小限制 webconfig
<?xml version="1.0" encoding="utf-8"?><configuration> <location p ...
- pygame学习之绘制移动的矩形
import pygame from pygame.locals import * pygame.init() screen = pygame.display.set_mode((600, 500)) ...
- Android 博客导航
Android 博客导航 一. 基础知识 Android 常用知识点 Android 常见问题解决 Android 常用控件 控件常用属性 Material Design 常用控件 二.常用知识点 动 ...
- 使用anaconda创建tensorflow环境后如何在jupyter notebook中使用
在以下目录中 C:\Users\UserName\AppData\Roaming\jupyter\kernels\python3 打开kernel.json文件,将python.exe文件的路径修改至 ...
- linux仅修改文件夹权限 分别批量修改文件和文件夹权限
比如我想把/var/www/html下的文件全部改成664,文件夹改成775,怎么做呢 方法一: 先把所有文件及文件夹改成664,然后把所有文件夹改成775 chmod -R 664 ./ find ...
- mac上安装iterm2的一些步骤记录
1.首先到item官网上下载item 下载地址 http://iterm2.com/ 2.把iitem2设置为默认终端: 3.设置快速打开关闭的hotkey 我们这里设置为command + T键 ...
- Scanner,Random,匿名对象-------------------java基础学习第七天
1.API 2.Scanner 功能:通过键盘输入数据到程序中. 引用类型的一般使用步骤: 导包 Import 包路径.类名称 只有java.lang 包写的类不需要导包,其他都需要 2.创建 类名称 ...
- NFS 系统搭建 - 成功
NFS是Network File System的缩写,即文件系统.客户端通过挂载的方式将NFS服务器端共享的数据目录挂载到本地目录下. 工作流程 1.由程序在NFS客户端发起存取文件的请求,客户端本地 ...