第05部分:表达式和运算符

表达式

相对于基本类型、字面量和变量,表达式是Java程序更高一级的结构。Java解释器会求出表达式的值,最简单的表达式叫基本表达式,由字面量和变量组成。例如,下面几个例子都是表达式:

1.7 // 一个浮点数字面量

true // 一个布尔字面量

sum // 一个变量

Java解释器计算字面量表达式得到的结果是字面量本身,计算变量表达式得到的结果是存储在变量中的值。



基本表达式没什么特殊意思。使用运算符把基本表达式连接在一起可以组成复杂的表达式。例如,下面的表达式使用赋值运算符(=)把两个基本表达式(一个变量,一个浮点数字面量)连在一起,组成赋值表达式:

sum = 1.7;

运算符不仅能连接基本表达式,也能在任意复杂度的表达式中使用。如下都是合法的表达式:

sum = 1 + 2 + 3 * 1.2 + (4 + 8)/3.0

sum/Math.sqrt(3.0 * 1.234)

(int)(sum + 33)




运算符

一门编程语言能编写什么样的表达式,完全取决于可以用的运算符。Java提供了丰富的运算符,但是在使用之前,要弄清楚两个重要的概念:优先级和结合性


下表总结了Java提供的运算符。P列和A列分支表示每类相关运算符的优先级和结合性。

1.优先级

在上图中,P列是运算符的优先级。优先级指定运算符执行的顺序,优先级高的运算符在优先级低的运算符之前运算。例如,有如下表达式:

a + b * c

乘号的优先级比加号的优先级高,所以结果是a和b乘以c的结果相加,这与小学数学上学到的一样。运算符的优先级可以理解为运算符和操作数之间绑定的紧密程度,优先级越高,绑定的越紧密。


运算符默认的优先级可以使用小括号改变,小括号能明确指定运算的顺序。前面那个表达式可以像下面这样重写,先相加再相乘:

(a + b)* c


Java采用的默认运算符优先级和C语言兼容,C语言的设计者选定的优先级无需使用括号就能流畅地写出大多数表达式,只有少量的Java惯用句法需要使用括号,例如:

((Integer) o).intValue();   // 类校正和成员访问结合在一起

while((line = in.readLine()) != null) { ... }   // 赋值和比较结合在一起

if ((flags & (PUBLIC | PROTECTED)) != 0) { ... }   // 位运算符和比较结合在一起



2.结合性

结合性是运算符的一个属性,定义如何计算有歧义的表达式。如果表达式中有多个优先级相同的运算符,结合性尤其重要。


大多数运算符由左至右结合,即从左向右计算。不过,赋值和一元运算符由右至左结合,在上图表中,A列是运算符或运算符组的结合性,L表示由左至右,R表示由右至左。


加号和减号的结合性都是由左至右。所以表达式a+b-c从左向右计算,即(a+b)-c。一元运算符和赋值运算符由右向左计算,例如下面这个复杂的表达式:

a = b += c = -~d

计算的顺序是:

a = (b += (c = -(~d)))


和运算符的优先级一样,运算符的结合性也建立了计算表达式的默认顺序。这个默认的顺序可以使用括号改变。然而,Java选定的默认运算符结合性是为了使用流畅的句法编写表达式,几乎不需要改变。




操作数的数量和类型

在上面运算符的图表中,第4列是每种运算符能处理的操作数数量和类型。有些运算符只有一个操作数,这种运算符叫一元运算符,例如一元减号的作用是改变单个数字的符号:

-n   //一元减号运算符

不过,大多数运算符都是二元运算符,有两个操作数。-运算符其实还有一种用法:

a - b   //减法运算符是二元运算符


Java还定义了一个三元运算符,经常称作条件运算符,就像是表达式中的if语句,它的三个操作数由冒号和问号分开,第二个和第三个操作数必须能转换成同一种类型:

x > y ? x : y    // 三元表达式;计算x和y哪个大


除了需要特定数量的操作数之外,每个运算符还需要特定类型的操作数。上面的图表中第4列是操作数的类型,其中使用的文本需要进一步说明:

数字:整数、浮点数或字符(即除了布尔类型之外的任何一种基本类型)。因为这些类型对应的包装类(例如 Character、Integer 和 Double)能自动拆包,所以在这些地方也能使用相应的包装类。

整数:byte、short、int、long 或 char 类型的值(获取数组元素的运算符 [ ] 不能使用 long类型的值)。因为能自动拆包,所以也能使用 Byte、Short、Integer、Long 和 Character类型的值。

引用类型:对象或数组。

变量:变量或其他符号名称(例如数组中的元素),只要能赋值就行。




返回类型

就像运算符只能处理特定类型的操作数一样,运算得到的结果也是特定类型的值。对算术运算符、递增和递减、位运算符和位移运算符来说,如果至少有一个操作数是 double 类型,返回值就是 double 类型;如果至少有一个操作数是 float 类型,返回值是 float 类型;如果至少有一个操作数是 long 类型,返回值是 long 类型;除此之外都返回 int 类型的值,就算两个操作数都是 byte、short 或 char 类型,也会放大转换成 int 类型。比较、相等性和逻辑运算符始终返回布尔值。各种赋值运算符都返回赋予的值,类型和表达式左边的变量兼容。条件运算符返回第二个或第三个操作数(二者的类型必须相同)。



副作用

每个运算符都会计算一个或多个操作数,得到一个结果。但是,有些运算符除了基本的计算之外还有副作用。如果表达式有副作用,计算时会改变 Java 程序的状态,即再次执行时会得到不同的结果。


例如,++ 递增运算符的副作用是递增变量中保存的值。表达式 ++a 会递增变量 a 中的值,返回递增后得到的值。如果再次计算这个表达式,会得到不同的值。各种赋值运算符也有副作用。例如,表达式 a\*=2 也可以写成 a=a\*2,这个表达式的结果是乘于 2 后得到的值,但是有副作用——把计算结果重新赋值给 a。


如果调用的方法有副作用,方法调用运算符 () 也有副作用。有些方法,例如 Math.sqrt(),只是计算后返回一个值,没有任何副作用。可是,一般情况下,方法都有副作用。最后,new 运算符有重大的副作用,它会创建一个新对象。



计算的顺序

Java 解释器计算表达式时,会按照表达式中的括号、运算符的优先级和结合性指定的顺序运算。不过,在任何运算之前,解释器会先计算运算符的操作数(&&、|| 和 ?: 例外,不会总是计算这些运算符的全部操作数)。解释器始终使用从左至右的顺序计算操作数。如果操作数是有副作用的表达式,这种顺序就很重要了。例如下面的代码:

int  a = 2;

int  v = ++a + ++a * ++a;

虽然乘法的优先级比加法高,但是会先计算 ++ 运算符的两个操作数。因为这两个操作数都是 ++a,所以得到的计算的结果分别是 3 和 4,因此这个表达式计算的是 3 + 4 * 5,结果为 23。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341

推荐阅读更多精彩内容