Java中三目运算符结合性究竟是什么?

首先,书上说的都是右结合性,甚至JLS中也明确的说了“The conditional operator is syntactically right-associative (it groups right-to-left). Thus, a?b:c?d:e?f:g means the same as a?b:(c?d:(e?f:g)).”
但是,如果是右结合性,有什么办法证明吗?我试着写了如下代码,却发现结果似乎在向我诉说三目运算符是左结合性的

String s = "abc";
int y = 1;
System.out.println("abc".equals(s) ? 1 : (++y) == 2 ? 0 : -1);
System.out.println(y);//1

如果是自右向左的结合性,那么(++y) == 2 ? 0 : -1 应该先被执行,也就是说y的值应该是2。但结果确是1……

我理解的结合性就是指在优先级相同的情况下,看是从左向右还是右向左。

自问自答吧。
stackoverflow上找到一种解释,我觉得还蛮不错。
就用a?b:c?d:e来说。
如果是左结合性,那么表达式等值于下((a?b:c)?d:e)。
于是乎变成了用(a?b:c)的结果,去决定究竟是返回d或者e。也就是说这个表达式只可能返回d或者e。这显然是不正确的。

7个回答

三目运算符是自右向左的结合性的把

caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 回复guangzhanzb: https://ask.csdn.net/questions/704617
接近 2 年之前 回复
guangzhanzb
guangzhanzb 能查到的所有资料都是说自右向左,但是没找到可以证明的例子……
3 年多之前 回复

官方文档有明确说法,右结合就不用怀疑了。
运算符的结合性,是指表达式如何解析,
因为右结合性,所以

 a ? b : c ? d : e  将被解析为  a ? b : ( c ? d : e )

也就是说后面的括号有没有都可以。
但并不影响表达式的求值。详细说明如下:

 "abc".equals(s) ? 1 : (++y) == 2 ? 0 : -1

对应if/else写法如下:

if ( "abc".equals(s) ) {
  return 1; //此时,整个表达式求值已经完毕,返回为1。
} else {
  if ( (++y) == 2 ) {
    return 0;
  } else {
    return -1;
  }
}

如果你将题目中换成

 "abcd".equals(s) ? 1 : (++y) == 2 ? 0 : -1)

再观察结果,就会有更深的体会。

fight_in_dl
战在春秋 回复guangzhanzb:很用心的回答问题,结果你采纳一个一句话的答案,伤人 ....。
3 年多之前 回复
caozhy
贵阳老马马善福专业维修游泳池堵漏防水工程 说得好
3 年多之前 回复
guangzhanzb
guangzhanzb 我感觉第一个条件改为false也无法说明是右结合性呀。而且按照您的说法,这也是更像是一个左结合性的,即先判断 "abcd".equals(s),有了结果后才去判断后面那个表达式
3 年多之前 回复

楼主,结合性说的是优先级相同时,从右往左结合,你看下边这段话:

f1() ? f2() : f3();

三个函数哪个先执行???显然f1是最先执行的,然后根据结果执行f2或者f3
而文档上说的 a?b:c?d:e 等价 a?b:(c?d:e) 是用于和 (a?b:c)?d:e 进行的区分。两个三目运算符,优先级相同,优先级相同时,从右往左结合,前者是左结合,后者是右结合。

扩展一下,会发现:
a?b:c?d:e?f:g的结合顺序有:((a?b:c)?d:e)?f:g、a?b:((c?d:e)?f:g)或a?b:(c?d:(e?f:g))三种结合方式,但是第三种才是从右向左的结合方式,也就是说,a?b:c?d:e?f:g默认的结合方式是第三种结合方式。但是表达式的执行顺序都是从左向右。

a?b:(c?d:(e?f:g))当a为true,返回b;当a为false,执行c?d:(e?f:g)
当c为true返回d;当c为false执行d:(e?f:g)。。。。。。类似于 f1() + f2() * f3(); 虽然乘号优先级比加号高 但是计算的时候 三个函数执行顺序还是 f1, f2, f3,就算你括号括起来 顺序也还是不变,运行自左向右。

总结:
结合----结合性----右结合性(优先级相同时,进行右结合)
运行----逻辑运算----从左向右

guangzhanzb
guangzhanzb 说的好,就是这个意思。可惜是在我已经解决之后才有的,否则一定采纳了。
3 年多之前 回复

三目运算符被短路,这不能证明左结合

System.out.println("abc".equals(s) ? 1 : ((++y) == 2 ? 0 : -1));
这么写,肯定右结合,但是因为第一个条件是ture,导致((++y) == 2 ? 0 : -1)可以不被求值。

guangzhanzb
guangzhanzb 请问有什么好的证明的例子吗?
3 年多之前 回复

楼上正解

System.out.println("abc".equals(s) ? 1 : ((++y) == 2 ? 0 : -1));后边的括号要不要都一样的。
建议你多试几次

 String s = "abc";
        int y = 1;
        System.out.println("abc".equals(s) ? 1 : (++y) == 2 ? 0 : -1);//1
        //因为"abc".equals(s)为true直接返回1,后边的不再执行所以第一句输出1

        //此时y值为1
        System.out.println(y);//1

还有,

 String s = "ab";//只要不是abc就行
        int y = 1;
        System.out.println("abc".equals(s) ? 1 : (++y) == 2 ? 0 : -1);//0
        //"abc".equals(s) 为false,执行 (++y) == 2 ? 0 : -1,由于(++y) == 2为true,返回0,所以输出0

        //此时y值为2
        System.out.println(y);//2
guangzhanzb
guangzhanzb 我感觉即便前面改为false,也无法说明它的结合性,而且按照您的思路,它是先判断前面的equals,有了结果后才去看后面的,这……这不就是左结合么
3 年多之前 回复

结合性,结合就一定要执行运算么?真是的!

打错了,更正下。。。

而文档上说的 a?b:c?d:e 等价 a?b:(c?d:e) 是用于和 (a?b:c)?d:e 进行的区分。两个三目运算符,优先级相同,优先级相同时,从右往左结合,前者是右结合,后者是左结合。

guangzhanzb
guangzhanzb 说的好,就是这个意思。可惜是在我已经解决之后才有的,否则一定采纳了。
3 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问