Java条件运算符的类型

当初学Java时听说过三目运算符,偶尔用到,也没在意,直到后来看到某到题目(文中第五段代码)懵逼了,于是看了下题解,自己又码了些代码测试以为自己懂了,直到后来又遇到某情况(文中有,读者自己找)又懵逼了,才发现条件运算符不是那么单纯。

三目操作符的基本功能

条件运算符(?:)是Java中唯一的三目运算符。因此对于Java提到三目操作符,均指条件运算符。条件运算符可以用来进行代替 if else 语句来简化条件分支跳转。例如以下一段常见的代码:

boolean b = true;//boolean b = false;
int a;
if(b) 
  a = 1; 
else 
  a = 2;

就可以用条件运算符简化为:

boolean b = true;//boolean b = false;
int a = b ? 1 : 2;

以上两段代码的意思都是:当布尔变量b是真时,a将赋值为1,b为false时,a将赋值为2。

所以条件运算符的一个基本用法是:

布尔变量a ? 表达式b : 表达式c; //(true)?1:2;

值得一提的是,b,c都不允许是void类型。

操作符两侧类型不同将会怎样

上面两段代码中,变量a和变量b都是int类型,所以没什么问题。那如果是不同类型会怎么样呢?

譬如这样:

boolean b = true;//boolean b = false;
int a = b ? 1.0 : 2;

甚至这样

boolean b = true;//boolean b = false;
int a = b ? 1 : new Object();

可以直接告诉读者,以上两段代码直接报错,因为不满足赋值语句一个基本的规则,右边必须是左边可以接受的类型。int显然不可能接受double,或者Object。

使用条件运算符给重载函数传参,且操作符两侧类型不同

你可能觉得事情就到此为止了,那不妨看看这看这两段代码:

boolean b = true;//boolean b = false;
System.out.println(b ? 1.0 : 2);

甚至这样

boolean b = true;//boolean b = false;
System.out.println(b ? 1.0 : new String("hello"));

或许就觉得有些困惑了,因为,毕竟System.out.print()方法具有大量重载,可以接受Java中所有的类型(即原始类型和对象的唯一根父类Object)。所以到底会不会报错呢?如果不报错,那么想必会出现类型转换,到底最终的类型会怎么决定呢?

是时候来点规则约束了–条件表达式的类型是什么?

讲真,这个规则有点复杂,推荐读者去看Oracle的官方Java语言文档15.25节。下面做一个简化规则介绍:

规则如下:

对于表达式 a ? b : c ,其类型由如下规则决定

  1. 如果b和c类型相同,那么表达式类型就是该类型。
  2. 如果b,c都是原始类型(即基本类型)或者原始类型的装箱类型,那么表达式将是某种原始类型,该原始类型是b,c中精度更高者。

下面对以上规则分别进行说明:

(1)如果a和b类型相同,那么表达式类型就是该类型。

这是最常见的使用场景,也是最安全的使用场景。

例如

System.out.println(a==4 ? "true" : "false");

(2)如果b,c都是原始类型或者基本类型的装箱类型,那么表达式将是某种原始类型,该原始类型是b,c中精度更高者。


//左边为int,右边为double

System.out.println(true ? 97 : 97.0);

//输出结果是97.0

这个例子很典型,int和double都是原始类型。在Java中,原始类型的精度排序从低到高是int(32位)->double(64位),因此int将会向上扩展位数转换为double。


//左边为char,右边为double

System.out.println(true ? 'a' : 2.0);

//输出结果是97.0

char是16位,会转成64位的double。


//左边为Character,右边为double

System.out.println(true ? new Character('a') : 2.0);

//输出结果是97.0

Character的拆箱类型是char,之后同上面的例子。

看似上面的规则已经行之有效,但是你或许会碰到下面的例子。

规则二的补充——int的特殊性

//左边为char,右边为int
System.out.println(true ? 'a' : 97);
//输出结果是a
//左边为char,右边为int
System.out.println(true ? 'a' : 65535);
//输出结果是a
//左边为char,右边为int
System.out.println(true ? 'a' : 65536);
//输出结果是97

第一个和第二个按照规则而看似应该是char转成int,然而事实并没有这样。这是因为int的特殊性,在java中可以直接使用数字对char进行赋值,而char的位数有16位,因此范围是0~2^16-1,也就是0~65535。譬如

char x=97;
System.out.println(a);
//输出a

是合法的语句,且输出是a,即ASCII码表中97对应的字符。因此,前两句中右边的值的类型会被判定为char。因此左右两边都是char。而第三个例子中65536已经超过了char的范围,必然是一个int了。因此左边的’a’会向更高精度的int转换输出97.

因此需要补充一个规则。

如果b和c中,有一个是类型T(仅限于char,byte,short),有一个是用int表示的类型T,则表达式的类型是类型T。

正如上面所说,在Java中,char,byte,short可以通过int来赋值的,在条件表达式中,b,c如果是char,byte,short之一和int,那么这时候int极有可能不被认为是整数了,只要它满足对应类型的 取值范围。

兼容性

在Java 4之前,条件运算符的b,c表达式如果类型不同,会直接编译报错。

总结

Java的三目操作符有时固然好用,但是一旦涉及操作符两侧类型不同,事情就不是那么容易看穿的了,所以还是慎用吧。

练习

判断以下表达式的类型

true ? 97 : 97 ; //int

true ? 97 : 97.0 ; //double

true ? ‘a’ : 97 ; //char

true ? 97 : ‘a’ ; //char

true ? 65536 : ‘a’; //int

true ? ‘a’ : 65536 ; //int

true ? 97 : new Integer(97); //int

true ? 97.0 : new Integer(97); //double

true ? 97 : new Double(97); //double

共有 0 条评论

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注