short s1 = 1; s1 = s1 + 1;我知道有错因为s1+1运算结果是int型,需要强制转换类型
但为什么short s1 = 1; s1 += 1;不会有错呢?

解决方案 »

  1.   

    对两个容量不一样的数据类型的变量进行算术运算时,java会自动将小容量的变量进行精度提升,然后再进行运算,得到的结果类型是提升后的大容量的数据类型.如果将该结果赋值给小容量的数据类型的变量,则必须进行强制的类型转换,否则编译程序会报损失精度错.如楼主示例,用i来表示1:
    short s1 = 1;
    int i = 1;
    首先,因为short类型是16位的,而int类型是32位的,在进行
    (s1+i) 运算时,自动将s1提升到32位,然后与i相加,得到的结果是32位的,而此时
    s1=s1+i; 必然报错,因为如果赋值成功,只是把低16位赋给了s1,这个虽然正是楼主想要的结果,但是编译程序却不能判定你的意图是什么.
    执行强转:
    s1=(short)(s1+i); 就没问题了.
    s1+=i;能编译通过并得到正确结果,而 s1=s1+i; 却报错,是因为它们并不像楼主认为的那样是等价的,s1+=i的方式java会对i进行窄化转换,由编译程序自动执行.
    java规范中说:
    E1 op=E2 实际上等价于 : E1=(T)( (E1)op(E2) )
    其中T是E1的数据类型.这种类型转换或者是一个恒等转换,或者是一个窄化转换.
    这个说明java是一种强类型的语言,对数据类型的要求是非常严格的,否则会引起混乱.
    下面解释一下三种类型转换:恒等转换(相同容量的两个数据类型之间的赋值);拓宽转换(小容量类型赋值给大容量类型);窄化转换(大容量赋值给小容量类型). 实际上,前两种转换都是编译程序自动执行的,而窄化转换则要求必须显式的执行.
      

  2.   

    我也有同样疑问,我试验过short s1 = 1; s1 += 1;  这个还真就不出毛病。待解中ing!
      

  3.   

    这个问题和+=的运算功能有关 
    第一种方式: 
    short s1 = 1; s1 = s1 + 1;需强行转化 
    因为short s1=1在栈中开辟了一个short类型的空间; 
    而s1=s1+1;中s1是short类型,在栈中开辟了一个short类型的空间,而1是int类型, 
    int类型比short类型大,所以相加后的结果应为比较大的类型,把s1+1的结果赋予short类型的变量s1,固然需要强行转化; 
    第二种方式: 
    short s1 = 1; s1 += 1;(可以正确编译) 
    由于+=运算符有自加功能,定义short s1 = 1;时,开辟了一个空间,当通过+=运算符运算时,只是在原来的栈中进行运算;不需强行转化;
      

  4.   

    JAVA中复合赋值操作符(包括上面的+=)进行运算时将自动地执行窄化原始类型转换,
    如上面的s1 += 1; 他的结果是short型的。
    而s1 = s1 + 1;“+”是不会窄化转换的,它执行时由于1是int的,结果也将隐式转换为int的。
      

  5.   

    我也有同样疑问,我试验过short s1 = 1; s1 += 1;  这个还真就不出毛病
      

  6.   

    这么多文盲说得跟真的一样.那你来跟我解释short s1 = 1;
    short s2 = 1;
    s1 = s1 + s2;//两个short相加为什么了是错的.
      

  7.   

    知道基本情况就可以了,要讲清楚就要去看jvm的指令了。
      

  8.   

    short s1 = 1; 
    short s2 = 1; 
    s1 = s1 + s2;//两个short相加为什么了是错的.
      

  9.   

    不要再深究了 。
    对于short类型 jvm没有提供运算支持,它们的运算都是通过提升为int进行的。
    举个例子 ,public class Test{
       public static void main(String[] args){
           short i=1;
           i+=1;
           short j=8;
           short k=(short)(i+j);
           System.out.println(i);
           System.out.println(j);
           System.out.println(k);
       }
    }bytecode:Compiled from "Test.java"
    public class Test extends java.lang.Object{
    public Test();
      Code:
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: returnpublic static void main(java.lang.String[]);
      Code:
       0: iconst_1      //常数1放入栈顶 
       1: istore_1      //存入 局部变量i,实现 赋值运算i=1
       2: iload_1       //读入i放到栈顶
       3: iconst_1      //常数1放入栈顶
       4: iadd          //int加法,计算i+1,结果放到栈顶
       5: i2s           //把int转换为short
       6: istore_1      //把short存入i
       7: bipush 8
       9: istore_2
       10: iload_1
       11: iload_2
       12: iadd
       13: i2s               //int转换为short
       14: istore_3
       15: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       18: iload_1
       19: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
       22: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       25: iload_2
       26: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
       29: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
       32: iload_3
       33: invokevirtual #3; //Method java/io/PrintStream.println:(I)V
       36: return}跟汇遍差不多,应该很容易理解,不过jvm的指令是基于栈的,不是基于寄存器的。
    关键看看i2s指令 ,i+=1;时编译器自动会加上强制转换语句
    其他情况下是需要自己强制转换
      

  10.   


    short s1 = 1; s1 = s1 + 1;我知道有错因为s1+1运算结果是int型,需要强制转换类型
    但为什么short s1 = 1; s1 += 1;不会有错呢?
    因为第一种是s1=s1+1这时s1又从新开辟拉一个新地址空间,跟原来的不一样啦,所以他的类型也不一样啦
    ,那么第二种没有重新开辟空间,还是原来的地址空间,所以类型还没有变化亚
      

  11.   

    类型比int小(char,byte,short),在运算前,会转换成int.结果当然也是int.
    ----Thinking in Java (4th)
    所以,你想要对的,只有
    s1 = (short)s1 + s2;
    PS:前面的是真高手,并非文盲....
      

  12.   

    用文字说明还是一楼的
    E1 op=E2 实际上等价于 : E1=(T)( (E1)op(E2) ) 
    能说明这个问题!
      

  13.   

    应该是
    s1 = (short)(s1 + s2);
    ....
      

  14.   

    在VC环境下试了一下,编译无误,printf("%d",s1)结果为2,也是正确的。
    哪位解释一下,是不是c环境下不存在此问题??