Java操作符真的简单到易如反掌?
之前我写了一篇《吃人的那些Java名词:对象、引用、堆、栈和堆栈》,本以为凭借自己8年的Java编程经验足够把这些“吃人”的Java名词解释清楚了,但有网友不以为然,在文章底部评论说:“老哥,你真的有8年java开发经验么。。。”(告诉我,为什么要用三个句号。。。而不是三个问号???)鉴于此,我在写这篇《Java操作符真的简单到易如反掌?》时感到惶恐不安,头顶三个大字几乎压得我喘不过气来,哪三个字呢? ——“臣有罪”,外加三个感叹号!!!。 但转念想到北航出版社董老师给我的建议: 你面对的是编程爱好者,或初级技术人员;所以不要担心,你把步骤写清楚,给人一种手把手的感觉,以实践和实例为主,技术原理为辅;让读者从简单开始,引导读者自己往深入的地方钻研。这样的话,你写作的目的也就达成了。 我惴惴不安的心情也就渐渐释然了——别担心那些抵触的声音,写好自己的文章就对了。 一、“=”号的宣言:我不是判官,我只是用来赋值的记得10年刚参加工作的时候,我的同事小王就因为一行简单的代码被领导骂的狗血喷头。当时小王被骂的那个惨啊,至今我还历历在目。究竟是一行什么代码呢?据我惨痛的回忆,大概是这样的: 我那同事小王很明显是想要判断b和c是否相等(==),然而却莫名其妙的少了一个=号,变成了赋值操作;我相信小王绝对不是故意的,只是当时急于和女朋友聊天少写了一个=号而已。但这样的错误竟然没有被编译器发现,因为当b和c是布尔(boolean)类型时,编译器就不会报错提示——这真是小之又小的概率,就这么不幸的被小王撞上了(重要的是被领导当众羞辱)——从此以后,小王对编程失去了信心,实习期没结束,小王就转行做汽车销售了。 悲哀啊! 我和小王相处的时间大概有3个月吧,对他的印象蛮好的,蛮聪明伶俐的一个少年;可惜被这样一个不经意的错误给耽搁了。 是时候给“=”号一个明确的宣言了:我不是判官,我只是用来赋值的;什么意思呢?意思是,取“=”号右边的值(右值),把它复制给左边(左值);右值可以是任何常数、变量或者生成一个值得表达式;但左值必须是一个明确的、已命名的变量。例如,可以将一个字符串赋值给一个变量: 关键点: 1)得到你的人却得不到你的心;来看这么一段代码: // 就当他俩结婚了
i = j; // 然而i却疯了 i = 250; // 但j却不为所动 怎么解释上面这段代码呢?答案是: 基本数据类型在赋值(生动而又不恰当的说法就是结婚吧)的时候,其实是把右值复制给了左值;但在左值发生改变的时候,右值却不会改变。这样的说法其实很绕,简单点的说法是基本类型的赋值是不会相互影响的,和对象引用的赋值是完全不同的;对象引用的赋值是会相互影响的。 2)你若不爱,我便不爱;来看这么一段代码:
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
}
} 怎么解释上面这段代码呢?答案是: 对象引用在赋值的时候,其实改变的是引用的地址; 3)有钱之后还能保持自我吗?来看这么一段代码:
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的基本算术操作符包括加号(+)、减号(-)、除号(/)、乘号(*)和取余(%);它们的使用方法就好像吃一口苹果那样简单,所以不再赘述。但需要注意一点,就是精度问题,来看这样一个示例:
你猜想o的输出结果肯定是38.4,因为m是6,n是6.4,它们的乘积自然是38.4啊!但你这样的猜想就好像买了一注大乐透;根据你设定的公式,这一注大乐透中一百万都是小的;但结果是,你又成功贡献了一次奖金池。为什么o的结果是38.400000000000006?为什么会这样?究竟为什么? 答案:首先,计算机进行的是二进制运算,我们输入的十进制数字会先转换成二进制,进行运算后再转换为十进制输出。double提供了快速的运算,然而问题在于转换为二进制的时候,有些数字不能完全转换,只能无限接近于原本的值,这就导致了在后来的运算会出现不正确结果的情况。 剧透:不止是double会有精度问题,float也会有精度问题。 那么,精度问题该怎么解决呢? BigDecimal !!!涉及到小数运算时一定要使用BigDecimal !!!不要使用double和float。 来看一下解决方案的代码:
有人说,为什么要用
讲究,特别的讲究。 三、害死人的自动递增,不偿命的自动递减记得参加工作的第二年,我的同事小二就因为把“前缀递增”写成了“后缀递增”被一顿痛骂之后拉出去祭天了。至今我还耿耿于怀,因为我也是参与者之一(当时小王准备使用 public static void calculate(int p) {
if (p < 3) { // 其他 calculate(p++); } } 按照以上的代码来看,这是一个死循环,calculate迭代是不会跳出的,直到程序报错。为什么会这样呢? 因为后缀递增会先生成值,再执行运算;也就是p++这个表达式的结果还是p。但前缀递增会先执行运算,再生成值;也就是++p这个表达式的结果是p+1。 那以上代码正确的写法是什么呢?答案如下: public static void calculate(int p) {
if (p < 3) { // 其他 calculate(++p); } }
四、我俩到底等不等?
System.out.println(q == r); // true
q = 128; 为什么一个是true,一个是false? 因为Integer作为常量时,对于-128到127范围之间的数,Java会对其进行缓存;也就是说 针对这个情况,在判断Integer是否相等时,尽量使用以下代码来进行判断:
注意:前提条件是q和r都不为null。 五、跳过的位移运算符对不起,我选择跳过! 六、特别的三元操作符来看这样一段代码:
三元操作符也称为条件操作符,它很简洁,也很特别,因为它有三个操作数: ?前面是布尔表达式,?后面是两个可选值(用:隔开),布尔表达式为true,则三元操作符的结果是value0,否则是value1。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |