首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

关于基本部类的简单赋值运算和复合赋值运算

2012-10-26 
关于基本类型的简单赋值运算和复合赋值运算本文版权归作者所有,仅供用来网上学习来用,读者可以收藏,请不要

关于基本类型的简单赋值运算和复合赋值运算
本文版权归作者所有,仅供用来网上学习来用,读者可以收藏,请不要下载到本机或重新发布到其它网站

有一道很经典的面试题是这样的:
short s1 = 1; s1 = s1 + 1; 有什么错? short s1 = 1; s1 += 1;有错吗?

答案很简单:
1. 编译出错。类型不匹配,需要强制类型转换。
2. 没有错误。

有一朋友说不是太明白这是为什么。我在这里分析一下原因。
对于前半部分:

short s1 = 1; s1 = s1 + 1;

   在java语言规范里,如果表达式中, 当对中间值的精确要求有时可能会超过任何一个操作数的范围, JVM会临时自动提升这个操作数的类型。
    像我们这个题目的前面部分,s1 + 1, 我们把类型写出来s1(short) + 1(int)这时JVM会自动把s1先提升成int,然后再跟后面的1(int)相加,这样就是int + int的运算了。但是为什么会有编译错误呢?因为int + int的结果还是int。我们看一下这个例子:
short s1 = 1;Object result = s1 + 1;System.out.println(result.getClass().getSimpleName());

结果是:
Integer

从结果可以看出,结果是int的包装类Integer。所以s1 + 1的结果是int类型的。因此把s1 + 1重新赋值给s1,即s1 = s1 + 1,会丢失精度,编译出错。

对于后半部分 s1 += 1,个人认为可以分为两部分,见下面代码:
short s1 = 1;s1 = (short)((int) s1 + 1);

这样解释的原因可以再看下面的例子:
public class Test {public void test1(){short s1 = 1;s1 = (short)((int) s1 + 1);}public void test2() {short s1 = 1;s1 += 1;}}

查看Test.class文件的字节码文件:
 public void test1();    0  iconst_1    1  istore_1 [s1]    2  iload_1 [s1]    3  iconst_1    4  iadd    5  i2s    6  istore_1 [s1]    7  return      Line numbers:        [pc: 0, line: 4]        [pc: 2, line: 5]        [pc: 7, line: 6]      Local variable table:        [pc: 0, pc: 8] local: this index: 0 type: Test        [pc: 2, pc: 8] local: s1 index: 1 type: short    public void test2();    0  iconst_1    1  istore_1 [s1]    2  iload_1 [s1]    3  iconst_1    4  iadd    5  i2s    6  istore_1 [s1]    7  return      Line numbers:        [pc: 0, line: 9]        [pc: 2, line: 10]        [pc: 7, line: 11]      Local variable table:        [pc: 0, pc: 8] local: this index: 0 type: Test        [pc: 2, pc: 8] local: s1 index: 1 type: short

    除了11-13行和28-30行的内的行号不同之外,其余部分都一样。即这两上写法其实是等效的。
    s1 = (short)((int) s1 + 1);  可以简化为s1 = (short)(s1 + 1);因为从short到int JVM会自动提升类型。

    最后补充一点,JVM会自动提升类型的表达式为:
short +|-|*|/|% short = (int) short +|-|*|/|% (int) short;byte  +|-|*|/|% byte  = (int) byte  +|-|*|/|% (int) byte;char  +|-|*|/|% char  = (int) char  +|-|*|/|% (int) char;

   因为这些类型的运算很容易就会越界。它们之间的任意组合都会先转换成int,然后再运算,结果为int类型。但是遇到更高精度的操作数,如float、double,它们也会向float、double自动提升类型。自动提升类型除基本赋值外,都是向精度高的方向进行的。
   对于short、byte、char的基本赋值,就像short s1 = 1;是int类型自动降低类型到short的。
   1 楼 hitjava 2009-05-10   想问下,有没有不用查看class的其它办法,如何确定s1 += 1后s1的类型 2 楼 tianlihu 2009-05-11   hitjava 写道
想问下,有没有不用查看class的其它办法,如何确定s1 += 1后s1的类型

我暂时没有办法,因为这个属于JDK底层的实现,s1 += 1这个表达式不能拆开,我也尝试过,没有成功,因为生成的字节码不一样,不能说明问题 3 楼 hitjava 2009-05-13   tianlihu 写道
hitjava 写道
想问下,有没有不用查看class的其它办法,如何确定s1 += 1后s1的类型 我暂时没有办法,因为这个属于JDK底层的实现,s1 += 1这个表达式不能拆开,我也尝试过,没有成功,因为生成的字节码不一样,不能说明问题

现在想来,只简单去想,s1本来就是short,最后赋值给s1时,它没有理由去变成另外一个类型

而且s1+1也只是在运算时使用了一个转换后的值。s1本身并没有变。

谢谢楼主啊 4 楼 hitjava 2009-05-13   不过只查看的话,可以用反射来看变量的类型。但是运算中的详细转换情况还是不能知道。

热点排行