A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© fantacyleo 金牌黑马   /  2014-7-3 22:32  /  8004 人查看  /  22 人回复  /   2 人收藏 转载请遵从CC协议 禁止商业使用本文

昨天和今天,看到两个跟赋值语句中类型转换有关的帖子:http://bbs.itheima.com/thread-126799-1-1.htmlhttp://bbs.itheima.com/thread-121036-1-1.html 。概括一下,涉及这么几个赋值语句:
1. short b = 1;
2. short b = 1; ++b;
3. short b = 1; b+=1;
4. short b = 1; b = b + 1;

前三段代码没问题,最后一段代码编译器会报错:cannot convert from int to short

我之前学过C,C标准规定,整数常量的类型是能容纳该整数的最小类型。所以在C中,b=b+1是不会报错的。Java不一样,Java语言规范明确说:整数常量如果末尾带L是long类型,不带L则是int类型(An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int )。所以1是int类型,b+1的结果是int类型,而b是short类型,int赋值给short又没有经过强转就会报错。按这个思路,++和+=为啥不报错?有人说++和+=会自动强转。好,我先接受这个说法。那么b=1为什么也不报错?

带着困惑,我又去查了Java语言规范。Java把short、byte提升到int这种情况称为widening conversion,把int转为short或byte这种情况称为narrowing conversion。在赋值时,Java要求赋值=右边的类型必须被转为=左边的类型。Java会自动执行5种转换,其中有widening conversion而没有narrowing conversion。所以, 上面第4段代码中b=b+1的右边是int,Java不会自动转为short,于是造成=左右类型不一致,报错。

好,问题来了:
short b=1 、++b 和 b+=1也有int转short的情况,为什么不报错?答案只能是:它们属于特殊情况。

对于short b = 1 Java语言规范说:如果=的右边是常量表达式,而且类型是byte、short、char或int,那么Java在必要时会自动执行narrowing conversion,只要这个常量表达式的值在=左边变量的取值范围之内(if the expression is a constant expression  of type byte, short, char, or int: A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable) 哦,原来如此!short b = 1; 1是常量表达式,类型是int,且在short的取值范围之内,所以Java自动强转,不会报错。但如果你写short b=200000,200000虽然是常量,但超过short取值范围,照样报错。


对于++, Java语言规范说:如有必要,++计算之后的结果会先执行narrowing conversion,再存入变量中(If necessary, the sum is narrowed by a narrowing primitive conversion  and/or subjected to boxing conversion (§5.1.7) to the type of the variable before it is stored)。也就是说,虽然b是short类型,但Java在++运算上的自动强转保证了++b不会报错
同样,对于+=Java也会自动强转。对于b+=1,Java会转成b = (short)(b+1)

因为之前受C语言的影响,这两天看到相关帖子,搞得我云里雾里。查了Java语言规范,总算是搞清楚了,发出来和大家分享一下

22 个回复

倒序浏览
真不错.学习了.
回复 使用道具 举报
这个不错的干货,学习了
回复 使用道具 举报
那么,楼主,求问:
  1. short i;
  2. i = 1 + 5;
复制代码

如此,是否会报错呢?

点评

报错!需要强转和赋初值  发表于 2015-3-6 15:24
回复 使用道具 举报
OCTSJimmy 发表于 2014-7-5 18:43
那么,楼主,求问:

如此,是否会报错呢?

如果不考虑i没有初始化的问题。那么:1+5是值为int类型的常量表达式,会自动向下转换,又1+5没有超过short的取值范围,因此不会报错
回复 使用道具 举报 1 0
fantacyleo 发表于 2014-7-5 18:55
如果不考虑i没有初始化的问题。那么:1+5是值为int类型的常量表达式,会自动向下转换,又1+5没有超过shor ...

了解了,多谢楼主,也就是说,赋值运算的右边,不论表达式多么复杂,只要满足:1、是常量 2、没有超过范围都会自动转换类型,以匹配等号左边。
:handshake
回复 使用道具 举报
OCTSJimmy 发表于 2014-7-5 18:43
那么,楼主,求问:

如此,是否会报错呢?

1+5是int类型的常量表达式且值在short的取值范围内,因此不会报错。 不止这样不会报错,你写:
final int x = 3; // 常量
short i = 3;
i = x + 5;
也不会报错。但如果再来一个int y=2; i=y+2就报错了。因为y+2不是常量表达式
回复 使用道具 举报
fantacyleo 发表于 2014-7-5 18:58
1+5是int类型的常量表达式且值在short的取值范围内,因此不会报错。 不止这样不会报错,你写:
final int  ...

那么,嗯例如:
  1. static final int x = 5;
  2. short s = 0;
  3. s = x + 6;
复制代码

如此呢?
另外,貌似
final属性的变量,可以用反射重新赋值的吧。
static final不行。
回复 使用道具 举报
OCTSJimmy 发表于 2014-7-5 19:03
那么,嗯例如:

如此呢?

反射我还没学到。。。不过局部变量不能声明为static。我猜想:java的编译器对赋值的要求是在编译时就能确定赋值的合法性,也就是=左边保证能接受=右边的值。那么有两种办法确定合法性:
1. =右边值的类型和=左边的变量类型一样,那肯定没问题。强转可以保证这一点。
2. 虽然左右类型不一样,但编译时就能确定=右边的值在=左边变量类型的取值范围内。那只能是常量表达式的值才能在编译时确定了,表达式中有变量就不行。
回复 使用道具 举报
fantacyleo 发表于 2014-7-5 19:13
反射我还没学到。。。不过局部变量不能声明为static。我猜想:java的编译器对赋值的要求是在编译时就能确 ...

修饰符还没看到,所以不会……

反射是以前玩Minecraft的MOD的时候,有玩到,所以有一点点了解。

多谢楼主!
回复 使用道具 举报
OCTSJimmy 发表于 2014-7-5 19:26
修饰符还没看到,所以不会……

反射是以前玩Minecraft的MOD的时候,有玩到,所以有一点点了解。

:handshake 互相交流、提高
回复 使用道具 举报
学习了,给楼主以及前面提问的童鞋赞一个
回复 使用道具 举报
来学习来学习来学习
回复 使用道具 举报
学习               对C不太了解
回复 使用道具 举报
学习到了
回复 使用道具 举报
再次涨姿势                                          
回复 使用道具 举报
mark一下
回复 使用道具 举报
马克  怕忘了
回复 使用道具 举报
来学习学习~
回复 使用道具 举报
本帖最后由 郑飞 于 2014-9-18 05:50 编辑

谢谢 楼主 有收获 能不能这么归纳: java是保证数据有效性的情况下尽量帮我们强转 (损失实际精度的事交给人来做决定)

如果可以这么理解的话就不用死记了
回复 使用道具 举报
12下一页
您需要登录后才可以回帖 登录 | 加入黑马