探讨一个关于三元运算的诡异问题

本人纯属虚构 2011-10-12 11:30:35
代码如下


public class Test{
public static void main(String args[ ]){
char ch = 'E';
int x = 3;
Object obj = false ? x : ch;
System.out.println(obj.getClass().getSimpleName());
System.out.println(false ? x : ch);
System.out.println(false ? 3 : 'E');
}
}


其执行结果为:

Integer
69
E

以前我一直以为是三元运算符前后类型不一样的时候 如果能互转 那么低位的会转成高位的

但是在这里出现了这个问题:三元运算符的前后直接用值和用相同值的变量 其结果不一样

有朋友对这个有清晰的理解没 分享一下...
...全文
481 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
本人纯属虚构 2011-10-14
  • 打赏
  • 举报
回复
3Q 3Q
  • 打赏
  • 举报
回复
双目数值类型提升

学名叫:binary numberic promotion


不要在条件运算的操作数中使用不同的数据类型,并且条件运算符与 if...else 结构性质并不是完全相同的。

下面是 Java Language Specification 上关于条件表达式的说明

● 如果第二和第三个操作数在可以转换为数值类型时,会有以下几种情况:
  ◆ 操作数其中一个是 byte 或 Byte 类型,而另一个是 short 或 Shoft 类型,那么这个表达式就是 shoft 类型
  ◆ 操作数中的一个是类型 T (T 可以是 byte、short 或者是 char 类型),而另一个是 int 类型的常数,其可以用 T 类型来表示时,那么这个表达式就是 T 类型
  ◆ 操作数中的一个是 Byte 类型,而另一个是 int 类型的常数,其可以用 byte 类型来表示,那么这个表达式就是 byte 类型
  ◆ 操作数中的一个是 Short 类型,而另一个是 int 类型的常数,其可以用 short 类型来表示,那么这个表达式就是 short 类型
  ◆ 操作数中的一个是 Character 类型,而另一个是 int 类型的常数,其可以用 char 类型来表示,那么这个表达式就是 char 类型
  ◆ 否则,双目数值提升(binary numeric promotion)会被用于操作数的类型中,条件表达式的类型是第二个和第三个操作数提升后的类型。注意:双目数值提升时进行拆箱转换和值集转换(value set conversion)

PS:这里只是部分的,更多的看 http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#341287

在这里会用到最后一点,即进行双目数值提升,所谓的双目数值提升通俗点的描述是:两个数根据一定的规则把其中一个的类型转为另一个类型。

根据 Java Language Specification 中关于双目数值提升的描述

http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#170983

● 如果任意一个操作数是引用类型,则会进行自动拆箱转换(unboxing conversion),然后:
● 如果任意一个操作数是 double 类型,那另外一个会被转换成为 double 类型
● 否则,如果任意一个操作数是 float 类型,那另外一个会被转换成为 float 类型
● 否则,如果任意一个操作数是 long 类型,那另外一个会被转换成为 long 类型
● 否则两个操作数都会被转换为 int 类型
本人纯属虚构 2011-10-13
  • 打赏
  • 举报
回复
1 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类
型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。
2 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作
数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条
件表达式的类型就是T。
3 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第
二个和第三个操作数被提升之后的类型。


以前看到过,不过还是没理解到含义
看起来很绕,主要的意思就是 只有当一个操作数是byte,short,char这三种 而另外一个操作数是int的时候
这种怪异的现象才会存在!
主要是第二点的"如果"和第三点的"否则"看起来很绕..
第三点的"否则"是对第二点"如果"后面的所有而言,还是针对"它的值是可以用类型T 表示的"而言?

抱歉 国语学得不是很好...

比如

public class DosEquis{
public static void main(String[] args){
double x = 90.9;
int i = 1;
System.out.println(true ? x : 0);
System.out.println(true ? i : x);
}
}

输出结果是
90.9
1.0


"3.否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第
二个和第三个操作数被提升之后的类型。"


是能提升的就提升,不能提升的就不提升?(比如String)

本人纯属虚构 2011-10-12
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 flagiris 的回复:]

Java code

char ch = 'E';
int x = 3;
Object obj1 = false ? x : ch;
Object obj2 = (false ? 3 : 'E');
System.out.println(obj1.getClass().getSimpleName());
……
[/Quote]

我这里的问题是为啥直接用值和用变量结果不一样呢..
菖蒲老先生 2011-10-12
  • 打赏
  • 举报
回复

char ch = 'E';
int x = 3;
Object obj1 = false ? x : ch;
Object obj2 = (false ? 3 : 'E');
System.out.println(obj1.getClass().getSimpleName());
System.out.println(obj2.getClass().getSimpleName());
System.out.println(obj1);
System.out.println(obj2);


执行结果:

Integer
Character
69
E
CloudX2019 2011-10-12
  • 打赏
  • 举报
回复
没有办法,公司用的1.4
本人纯属虚构 2011-10-12
  • 打赏
  • 举报
回复
说明一下:jdk 1.6.0_27

楼上的怎么还在用1.4阿...

1.5以上应该都是这个结果吧..
CloudX2019 2011-10-12
  • 打赏
  • 举报
回复
我用jdk1.4 这样写报语法错误
wingson_shen 2011-10-12
  • 打赏
  • 举报
回复
不懂。。帮顶了。
菖蒲老先生 2011-10-12
  • 打赏
  • 举报
回复
• 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作
数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条
件表达式的类型就是T。
• 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第
二个和第三个操作数被提升之后的类型。

学习了。。。
一天zijie一夜 2011-10-12
  • 打赏
  • 举报
回复
谜题8:Dos Equis
这个谜题将测试你对条件操作符的掌握程度,这个操作符有一个更广为人知的名
字:问号冒号操作符。下面的程序将会打印出什么呢?
public class DosEquis{
public static void main(String[] args){
char x = 'X';
int i = 0;
System.out.println(true ? x : 0);
System.out.println(false ? i : x);
}
}
这个程序由两个变量声明和两个print 语句构成。第一个print 语句计算条件表
达式(true ? x : 0)并打印出结果,这个结果是char 类型变量x 的值’X’。而
第二个print 语句计算表达式(false ? i : x)并打印出结果,这个结果还是依
旧是’X’的x,因此这个程序应该打印XX。然而,如果你运行该程序,你就会
发现它打印出来的是X88。这种行为看起来挺怪的。第一个print 语句打印的是
X,而第二个打印的却是88。它们的不同行为说明了什么呢?

答案就在规范有关条件表达式部分的一个阴暗的角落里。请注意在这两个表达式
中,每一个表达式的第二个和第三个操作数的类型都不相同:x 是char 类型的,
而0 和i 都是int 类型的。就像在谜题5 的解答中提到的,混合类型的计算会引
起混乱,而这一点比在条件表达式中比在其它任何地方都表现得更明显。你可能
考虑过,这个程序中两个条件表达式的结果类型是相同的,就像它们的操作数类
型是相同的一样,尽管操作数的顺序颠倒了一下,但是实际情况并非如此。

确定条件表达式结果类型的规则过于冗长和复杂,很难完全记住它们,但是其核
心就是一下三点:
• 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类
型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。
• 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作
数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条
件表达式的类型就是T。
• 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第
二个和第三个操作数被提升之后的类型。

2、3 两点对本谜题是关键。在程序的两个条件表达式中,一个操作数的类型是
char,另一个的类型是int。在两个表达式中,int 操作数都是0,它可以被表
示成一个char。然而,只有第一个表达式中的int 操作数是常量(0),而第二
个表达式中的int 操作数是变量(i)。因此,第2 点被应用到了第一个表达式
上,它返回的类型是char,而第3 点被应用到了第二个表达式上,其返回的类
型是对int 和char 运用了二进制数字提升之后的类型,即int。
条件表达式的类型将确定哪一个重载的print 方法将被调用。对第一个表达式来
说,PrintStream.print(char)将被调用,而对第二个表达式来说,
PrintStream.print(int)将被调用。前一个重载方法将变量x 的值作为Unicode
字符(X)来打印,而后一个重载方法将其作为一个十进制整数(88)来打印。
至此,谜题被解开了。
总之,通常最好是在条件表达式中使用类型相同的第二和第三操作数。否则,你
和你的程序的读者必须要彻底理解这些表达式行为的复杂规范。
对语言设计者来说,也许可以设计一个牺牲掉了部分灵活性,但是增加了简洁性
的条件操作符。例如,要求第二和第三操作数必须就有相同的类型,这看起来就
很合理。或者,条件操作符可以被定义为对常量没有任何特殊处理。为了让这些
选择对程序员来说更加容易接受,可以提供用来表示所有原始类型字面常量的语
法。这也许确实是一个好注意,因为它增加了语言的一致性和完备性,同时又减
少了对转型的需求。


摘自JAVA解惑
zhaoct 2011-10-12
  • 打赏
  • 举报
回复
主要是 System.out.println(false ? 3 : 'E');里的3是常量还是变量决定的。。。
zhaoct 2011-10-12
  • 打赏
  • 举报
回复
java puzzlers:

• 如果第二个和第三个操作数具有相同的类型,那么它就是条件表达式的类
型。换句话说,你可以通过绕过混合类型的计算来避免大麻烦。
• 如果一个操作数的类型是T,T 表示byte、short 或char,而另一个操作
数是一个int 类型的常量表达式,它的值是可以用类型T 表示的,那么条
件表达式的类型就是T。
• 否则,将对操作数类型运用二进制数字提升,而条件表达式的类型就是第
二个和第三个操作数被提升之后的类型。
zhaoct 2011-10-12
  • 打赏
  • 举报
回复
好想在java解惑里看到过。。。

67,513

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧