【1】您确定真正了解后缀表达式与前缀表达式的区别吗?

public class IncrementDemo{
public static void main(String[] args) {
int i = 0;
int j = 0;
i = i++;
j = ++j;
System.out.printf("i=%d,j=%d \n",i,j);
}
}

输出结果是什么呢?

关于前缀表达式与后缀表达式,JLS中是这样解释的:

1.The value of the postfix increment expression is the value of the variable before the new value is stored. JLS 15.14.2

2.The value of the postfix decrement expression is the value of the variable before the new value is stored. JLS 15.14.3

3.The value of the prefix increment expression is the value of the variable after the new value is stored.JLS 15.15.1tt

4.The value of the prefix decrement expression is the value of the variable after the new value is stored.JLS 15.15.2

翻译过来就是:

1.后缀表达式的返回值为新值被存储之前的变量的值

2.前缀表达式的返回值为新值被存储之后的变量的值

因此;上面的代码设计上可以理解为

public class IncrementDemo{
public static void main(String[] args) {
int i = 0;
int j = 0;
i = i++;//int temp = i;i = i + 1;return temp;
j = ++j;// j = j + 1;return j;
System.out.printf("i=%d,j=%d \n",i,j);
}
}

【2】 i%2 == 1 是什么梗?

在《Java解惑》中的第一个谜题就是判断一个数是否为奇数,想到这里,你可能马上会想起关于奇数的定义:

能被2整除的数是偶数,不能被2整除的数是奇数

你可能马上会写出这样的函数

public static boolean isOdd(int i){
return i%2 == 1;
}

但是你看了片刻之后,好像记得曾经在哪里看过判断奇偶性有些坑,但是想不起为什么会有坑。

OK,关于数的取余操作确实有些与我们的常识有所出入的地方。

关于取余的操作规则,JLS中是这样规定的:

The remainder operation for operands that are integers after binary numeric promotion produces a result value such that (a/b)Xb+(a%b) is equal to a .JLS 15.17.3

It follows from this rule that the result of the remainder operation can be negative only if the dividend is negative, and can be positive only if the dividend is positive.JLS 15.17.3

按照规则,我们可以将 a%b 等效为 a - a / b X b;

从中我们可以看出 a%b 的结果的正负与 a 相同,所以一旦a为负数,那么该判断奇偶的方法就失效了。

所以正确的判断方法是:

public static boolean isOdd(int i){
return i%2 != 0; // 或者 return (i & 1) !=0;
}

【3】 i += 1 ; 不等价于 i = i + 1;?

看到这里,你可能要骂爹了,明明没有却别的两个表达式怎么可能不等价呢?您不妨看一下下面的例子

public class OperatorDemo{
public static void main(String[] args) {
byte b1 = 1;
byte b2 = 1;
b1 += 1;
b2 = b2 + 1;
System.out.printf("b1 = %d , b2 = %d \n",b1,b2);
}
}

当你尝试编译这个程序的时候发现它报错了。

OperatorDemo.java:7: 错误: 不兼容的类型: 从int转换到byte可能会有损失
b2 = b2 + 1;
^

什么?b2 + 1 的结果为int类型,好吧,整数字面量的默认类型为 int 他可能自动转型了。

那你再试试这个程序

public class OperatorDemo{
public static void main(String[] args) {
byte b = 1;
byte b1 = 1;
byte b2 = 1;
b1 += b;
b2 = b2 + b;
System.out.printf("b1 = %d , b2 = %d \n",b1,b2);
}
}

这下他该没问题了吧,再编译运行一下看看,what! 怎么还是报错了?

OperatorDemo.java:19: 错误: 不兼容的类型: 从int转换到byte可能会有损失
b2 = b2 + b;
^

怎么两个byte相加结果还是为 int 呢?还有,为什么没有 b1 += b 与 b1 += 1一直没有报错呢?

好吧,这时我们我们还是得祭出我们的大杀器 JLS了。

在JLS中关于复合赋值语句是这样描述的

A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)) , where T is the type of E1 , except that E1 is evaluated only once. JLS 15.26.2

翻译过来就是复合赋值语句会隐式地对结果进行强转,b1 += 1 相当于 b1 = (byte) ( b1 + 1); 这下能够理解为什么 b1 += b 与 b1 += 1一直没有报错了吧,但是为什么两个byte类型的数字相加得到的是int类型的结果呢?别急,JLS中关于加法的运算规则是这样描述的

The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands. Binary numeric promotion is performed on the operands.The type of an additive expression on numeric operands is the promoted type of its operands.JLS 15.18.2

怎么感觉在扯淡呢,二元 + 操作符在运用于数字类型的两个操作数时,会执行加法,并产生操作数的和,在操作数上会执行二元数字的提升,返回值类型是操作数提升后的类型。等等二元数字提升是什么鬼? 再找找喽。

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:

  1. If any operand is of a reference type, it is subjected to unboxing conversion
  2. Widening primitive conversion is applied to convert either or both

    operands as specified by the following rules:

    • If either operand is of type double , the other is converted to double .

    • Otherwise, if either operand is of type float , the other is converted to float .

    • Otherwise, if either operand is of type long , the other is converted to long .

    • Otherwise, both operands are converted to type int .

    After the conversion(s), if any, value set conversion is then applied to

    each operand.

Bingo,终于找到答案了!

  1. 如果两个操作数中只要有一个为double则另外一个就将转换为double,
  2. 否则如果两个操作数中有一个为float则另外一个就将转换为float,
  3. 否则如果两个操作数中有一个为long则另外一个就将转换为long,
  4. 否则,两个操作数都被转换为 int 类型

    看来这 byte、short、char 之间相加都会转换为 int 类型啊。 值得注意的是在 +、-、X、/、% 时都存在二元数字提升

OK,看到这里想必您应该解决了一些疑惑吧,但是还没完...

【4】某谭什么时候出了《Java语言程序设计》?

public class OperatorDemo{
public static void main(String[] args) {
int i = 1;
int k = 1;
int j = (i=2) * i; //expression 1
i = 1;
i += (i=2) * i; //expression 2
j = j + (j=2); //expression 3
k += (k=4) * (k+2); //expression 4
System.out.printf("i=%d,j=%d,k=%d",i,j,k);
}
}

怎么,某谭什么时候出了《Java语言程序设计》?好吧,博主也认为这一类型的题目简直是语言垃圾,谁特么会写这样的代码!

但是,很无奈,一些坑爹的考试偏偏喜欢考这种题目。好吧继续看吧。

我们都知道Java中,一般情况下表达式是自左向右进行计算的。

  1. 运算符右边的表达式肯定比右边先执行!
  2. 但是在复合赋值中,左端的值是在右端计算之前保存的。

1.The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

2.Value Of Left-Hand Side Of Compound Assignment Is Saved Before

Evaluation Of Right-Hand Side

expression 1

int j = (i=2) * i;

乘号左边的表达式为 (i=2)先执行,所以i变成了2 所以等效于 int j = 2 X 2 = 4;

expression 2

i += (i=2) * i;

乘号左边的表达式为 (i=2)先执行,所以i变成了2 所以等效于 i += 2 X 2; 但是 左端的值 i = 1 是在右端计算之前保存的,

所以结果为 i = 1+(2 X 2)=5

expression 3

j = j + (j=2);

加号右边的表达式为 (j=2)后执行,所以等效于 j = 4 + 2 = 6;

expression 4

k += (k=4) * (k+2);

乘号左边的表达式为 (k=4)先执行,所以k变成了4 表达式等效于 k += 4X(4+2); 但是 左端的值k = 1 是在右端计算之前保存的,

所以结果为 k = 1+4X(4+2)= 25

即输出

i=5,j=6,k=25

怎么样,现在你的一些疑惑应该解决了吧。

圉于博主的水平,理解可能有所偏差,还望各位大佬不吝指正!

参考:The Java Language Specification, Java SE 8 Edition

Java表达式中的那些坑的更多相关文章

  1. Java面试中遇到的坑【填坑篇】

    看到大家对上篇<Java面试中遇到的坑>一文表现出强力的关注度,说明大家确实在面试中遇到了类似的难题.大家在文章留言处积极留言探讨面试中遇到的问题,其中几位同学还提出了自己的见解,我感到非 ...

  2. 避坑手册 | JAVA编码中容易踩坑的十大陷阱

    JAVA编码中存在一些容易被人忽视的陷阱,稍不留神可能就会跌落其中,给项目的稳定运行埋下隐患.此外,这些陷阱也是面试的时候面试官比较喜欢问的问题. 本文对这些陷阱进行了统一的整理,让你知道应该如何避免 ...

  3. Java 面试中遇到的坑

    Java开发中很多人都不愿意修改自己以前的代码,看别人的代码更是无法忍受,当看到别人代码里面一些匪夷所思的写法实现时,恨不得找到负责人好好跟他谈谈心,那么你在开发中是不是也使用到以下几种实现呢. 1. ...

  4. java学习过程中遇到的坑及解决方法

    1. Table 'my_data_base.gjp_zhangwu' doesn't exist Query: select * from gjp_zhangwu Parameters: 数据库中的 ...

  5. Java面试中遇到的坑【篇二面试干货】

    俗话说早起的鸟儿有虫吃,现在临年关越来越近,有跳槽的想法的同事也都打算年前做好功课年后入职,所谓年终奖拿了,工作换的也是水到渠成. 说到这里想必有同学要说了,年底了放着年终奖不拿为何要跳槽呢?这个就要 ...

  6. java表达式中运算符优先级

    运算符优先级:运算符*和/(以及%)的优先级高于+和-(优先级越高,越早运算) 在逻辑运算符中,!拥有最高优先级,之后是&&,接下来是||. 一般来说,相同优先级的运算符的运算顺序是从 ...

  7. python中lambda表达式中自由变量的坑,因为for循环结束了 变量还保存着,详见关于for循环的随笔

    http://blog.csdn.net/u010949971/article/details/70045537

  8. java、el表达式中保留小数的方法

    Java中: import java.math.BigDecimal; import java.text.DecimalFormat; import java.text.NumberFormat; p ...

  9. java 8 中lambda表达式学习

    转自 http://blog.csdn.net/renfufei/article/details/24600507 http://www.jdon.com/idea/java/10-example-o ...

随机推荐

  1. jQuery 的 ready 函数是如何工作的?(源码分析)

    如果你使用过 jQuery , 就必然使用过 ready 函数,它用来注册当页面准备好之后可以执行的函数. 问题来啦,我们的页面什么时候准备好了呢? 1. onload 事件 最基本的处理方式就是页面 ...

  2. 微信小程序来了,小程序都能做些什么

    2017年的微信大动作就是微信小程序了,到底小程序都能做些什么?这是很多人关注的热点,小程序开发对企业又有什么帮助呢?下面让厦门微信小程序开发公司来为你就分析下.       微信小程序与APP的关系 ...

  3. swift Alamofire请求数据与SwiftJson解析

    一直在研究swift 程序最重要的是什么???答案当然是数据啦.  数据对一个程序的影响有多大自己想去吧!!!如果你非要说不重要,那你现在就可以关网页了  哈哈哈哈哈 我呢  swift新手  菜鸟一 ...

  4. Spring MVC 返回NULL时客户端用$.getJSON的问题

    如果Spring MVC返回是NULL,那么客户端的$.getJSON就不会触发: 必须返回点什么东西: 如果返回的是一个字符串,客户端的$.getJSON也不会触发:把字符串 包装成List< ...

  5. JavaScript原生的节点操作

    前言:原生是Javascript的基础,还是需要多多重视,时间长都忘记了,现在整理一下. 获取子节点 children 不是标准的dom属性,但是几乎被所有浏览器支持.不包含文本节点. 注意:在IE中 ...

  6. Centos6.5 mysql折腾记

    1.yum安装mysql [root@localhost ~]# yum -y install mysql-server 安装结果 Installed: mysql-server.x86_64 0:5 ...

  7. iOS多线程——GCD与NSOperation总结

    很长时间以来,我个人(可能还有很多同学),对多线程编程都存在一些误解.一个很明显的表现是,很多人有这样的看法: 新开一个线程,能提高速度,避免阻塞主线程 毕竟多线程嘛,几个线程一起跑任务,速度快,还不 ...

  8. iOS视频压缩处理

    最近忙于项目开发, 昨天才完成整个项目的开发, 今天就抽出时间, 分享一下我在开发中所涉及到的技术问题! 由于近期开发涉及到视频, 所以视频压缩, 上传, 播放等一系列功能都是要涉及到的, 所以在此, ...

  9. 【鸡年大吉】,不知道写点啥,放个demo(小球碰撞)吧,有兴趣的看看

    最初的想法是仿写win7的泡泡屏保效果,但是对于小球的斜碰问题一直没搞明白(如果你会这个,欢迎留言或者做个demo),所以只是简单处理了碰撞后的速度,有时候会看起来很搞笑~~~funny guy 话不 ...

  10. 笔记之《用python写网络爬虫》

    1 .3 背景调研 robots. txt Robots协议(也称为爬虫协议.机器人协议等)的全称是"网络爬虫排除标准"(Robots Exclusion Protocol),网站 ...