java short s=1为什么不报错,java的问题,关于short类型的
大家好,今天小编来为大家解答以下的问题,关于java short s=1为什么不报错,java的问题,关于short类型的这个很多人还不知道,现在让我们一起来看看吧!
javashort怎么-1
注:如未特别说明,Java语言规范 jls均基于JDK8,使用环境是 eclipse4.5+ win10+ JDK 8
本篇的知识点,主要是涉及到 Java中一些比较常见的默认窄化处理(Java编译器自动添加的),这里将从一个问题开始,据说这也是一道常见的笔试题/面试题:
为什么 short i= 1; i+= 1;可以正确编译运行而 short i= 1; i= i+ 1;会出现编译错误?
其他说法:都放在一起编译会出现有什么结果,哪一行报错?为什么?
笔者注:其实这其中会涉及到一些编译优化和底层的知识,限于知识面,本篇不涉及,如有需要,可自行搜索。
本文的目录结构如下:
1、结论
关于开篇提出的问题,这里先直接给出结论:
Java语言规范规定基础数据类型运算默认使用32位精度的int类型
只要是对基本类型做窄化处理的,例如 long-> int-> short-> char,都需要做强制转换,有些是Java编译器默认添加的,有的则是代码中显式做强制转换的。
short i= 1; i+= 1;可以正确编译运行是因为Java编译器自己添加了强制窄化处理,即对于任何的T a; X b; a+= b;等价于T a; X b; a=(T)(a+ b);Java编译器会默认做这个显式强制转换(尽管有时候会出现精度问题,例如 b是 float、 double类型,强烈建议不要有这样的操作)。前面的i+= 1其实就等价于i=(int)(i+ 1),即便将数字1换成是double类型的1.0D也是如此。
short i= 1; i= i+ 1;编译不通过的原因就很明显了:无论是代码中,还是Java编译器,都没有做强制转换,int类型直接赋给 short,因此编译出错。
对于常量(数字常量、常量表达式、final常量等),Java编译器同样也可以做默认的强制类型转换,只要常量在对应的数据范围内即可。
2、详解
接下来讲详细分析为什么 short i= 1; i+= 1;可以正确编译而 short i= 1; i= i+ 1;则会编译失败。先列一下搜出来的一些令人眼前一亮(or困惑)的代码
public static voidmain(String[] args){//注:short∈ [-32768, 32767]
{/** 1、对于+=,-=,*=,/=, Java编译器默认会添加强制类型转换,
*即 T a; X b; a+= b;等价于 T a; X b; a=(T)(a+ b);*/
//0是int类型的常量,且在short范围内,被Java编译器默认强制转换的
short i= 0;
i+= 1;//等价于 i=(short)(i+ 1);
System.out.println("[xin01] i="+ i);//输出结果: 1
i=(short)(i+ 1);
System.out.println("[xin02] i="+ i);//输出结果: 2
/**下面这2行都会有编译报错提示:
* Exception in thread"main" java.lang.Error: Unresolved compilation problem:
* Type mismatch: cannot convert from int to short
* [注]错误:不兼容的类型:从int转换到short可能会有损失
* Eclipse也会有提示: Type mismatch: cannot convert from int to short*/
//i= i+ 1;//i= 32768;
i= 0;
i+= 32768;//等价于 i=(short)(i+ 32768);下同
System.out.println("[xin03] i="+ i);//输出结果:-32768
i+=-32768;
System.out.println("[xin04] i="+ i);//输出结果: 0
i= 0;long j= 32768;
i+=j;
System.out.println("[xin05] i="+ i);//输出结果:-32768
i= 0;float f= 1.23F;
i+=f;
System.out.println("[xin06] i="+ i);//(小数位截断)输出结果: 1
i= 0;double d= 4.56D;
i+=d;
System.out.println("[xin07] i="+ i);//(小数位截断)输出结果: 4
i= 10;
i*= 3.14D;
System.out.println("[xin08] i="+ i);//输出结果: 31
i= 100;
i/= 2.5D;
System.out.println("[xin09] i="+ i);//输出结果: 40
}
{/** 2、常量表达式和编译器优化:常量折叠*/
//2* 16383= 32766//(-2)* 16384=-32768//都在 short范围内,常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换
short i= 2* 16383;//等价于 short i=(short)(2* 16383);
short j=(-2)* 16384;//2* 16384= 32768,超过 short范围,编译器不会做转换//Type mismatch: cannot convert from int to short//short k= 2* 16384;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换
short cThirty= 3* 10;short three= 3;short ten= 10;//Type mismatch: cannot convert from int to short//short thirty= three* ten;
final short fTthree= 3;final short fTen= 10;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换
short fThirty= fTthree*fTen;final short a= 16384;final short b= 16383;//常量表达式在编译优化后直接用对应的常量结果,然后编译器做强制转换
short c= a+b;
}
}
接下来根据代码罗列的两部分分别进行说明:
2.1、对于+=,-=,*=,/=, Java编译器默认会添加强制类型转换,即 T a; X b; a+= b;等价于 T a; X b; a=(T)(a+ b);
A compound assignment expression of the formE1 op= E2is equivalent toE1=(T)((E1) op(E2)), whereTis the type ofE1, except thatE1is evaluated only once.
For example, the following code is correct:
short x= 3;
x+= 4.6;
and results in x having the value 7 because it is equivalent to:
short x= 3;
x=(short)(x+ 4.6);
笔者注:
实际上,直接加上强制类型转换的写法,也是大家都熟悉且理解起来最清晰的方式,可以避免可能潜在的类型不匹配时出现的精度损失问题,使用的时候需要注意。当然,笔者认为这些方式都没有好坏之分,正确地使用即可。
Java从语言规范层面对此做了限制。有兴趣的还可以通过 class文件和 javap-c反汇编对所使用的字节码作进一步的研究。
知道了Java语言相关的规范约定,我们就可以看出,与之对应的是以下这种出现编译错误的写法(报错提示:Type mismatch: cannot convert from int to short):
short i= 1;//i+ 1是 int类型,需要强制向下类型转换
i= i+ 1;
2.2、常量表达式和编译器优化:常量折叠
需要注意的是,前面的示例short x= 3;中的3其实默认是 int类型,但是却可以赋值给short类型的x。这里涉及到到的其实是常量表达式。
In addition, if the expression is a constant expression(
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.
A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:
Byte and the value of the constant expression is representable in the type byte.
Short and the value of the constant expression is representable in the type short.
Character and the value of the constant expression is representable in the type char.
对于常量表达式,其结果是可以自动做窄化处理的,只要是在对应的数据类型范围内,Java编译器就进行做默认强制类型转换。
Some expressions have a value that can be determined at compile time. These are constant expressions(
true(short)(1*2*3*4*5*6)
Integer.MAX_VALUE/ 2
2.0*Math.PI"The integer"+ Long.MAX_VALUE+" is mighty big."
A constant variable is a final variable of primitive type or type String that is initialized with a constant expression(
通过常量表达式赋值的final变量都是常量,这种也是编译期可以确认最终值,会通过编译优化直接赋予最终值,而且可以直接依靠编译器做窄化处理。
对于这一块,其实对应的是一个比较基础的编译器优化:常量折叠(Constant Folding),有兴趣的可以自行搜索。stackoverflow上由相关的讨论,参考[9]、[10]、[11]
笔者注:
尽管常量表达式最终都被编译器优化为直接值,但是为了清晰,提高可读性、可维护性,代码中没必要对常量直接换算,例如一天 24* 60* 60秒,其实可以分别用可读性更强的final常量来表示。
Bloch大神的 Java Puzzlers中也有相关的一些说明,有兴趣的可以去看看
java的问题,关于short类型的
首先看“s= s+ 1”为什么错。
Java编译器认为一个像“1”这样的直接数是一个int型。Java的自动类型转换是一个占用空间少的类型可以自动转换成占用空间大的类型,反之则必须强制类型转换,否则报错。“s+ 1”这个表达式因为是short型和int型相加,因此自动转换成了int型,此时再用“s= s+ 1”赋值给一个short型而没有强制类型转换那么自然报错。
而至于为什么 s+= 1没有错我认为没有必要深入研究,你既然发现了这个事实,那么知道就行了,也许Java的设计者当初对它做了特殊处理。
java的+号和数据转换问题
关于第一问题的回答:
首先,java中基本数据类型:
1从小类型到大类型.自动转换
bytea=1;intb=a;
2从大类型到小类型,强制转换.(因为可能有精度丢失等问题,强制转换自己可以先思考先能不能转换)
inta=1;byteb=(byte)a;
intx=158;bytey=(byte)x;
//byte的范围是-128~127x超过范围了,强制转换得到一个-98
//所以强制转换前需要思考,会不会超过范围
其次:结合题目思考.java基本数据类型的运算
Java中,对于short, byte, char比int小的变量类型来说,运算结果会自动转换为int类型。使用 int类型作为运算类型
byte a= 1; byte b=2;
所以如果a+b.那么结果是什么类型. int类型
如果赋值给byte c= a+b;//运行时就会报错:Type mismatch: cannot convert from int to byte
解决办法如下:
第一种:
bytec=(byte)a+b;//确定不超过byte范围时.强制转换
第二种
intc=a+b;//int或者long.其实写成longc,就是把int类型的结果,又自动转换成了long
第三种
拓展,其实用final修饰后的变量,可以直接进行运算,不用转换类型
finalbytem=1,n=2;
byteresult=m+n;//就不会出错,当然还是要注意是否超过byte范围.
java面对final修饰的基本数据类型的变量m和n,其实当成了直接赋值.就好比
byte result= 1+2;
关于第二个问题的回答:
System.out.println("结果为:"+result);这里的+号是连接符,把字符串和其他数据连接在一起.
+号运算符.根据情况不同.要么进行计算,要么有字符串作为其中的一个操作数时,就进行字符串的连接.
System.out.println("2"+"+"+"3"+"="+(2+3));
//括号里的优先计算先计算2+3=5,然后把整个字符串.串联起来
//输出2+3=5
关于本次java short s=1为什么不报错和java的问题,关于short类型的的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。