问题
Why can I do this:
short a = 5;
But not this:
void setNum(short a);
setNum(5);
It throws:
Possible lossy conversion from int to short
I understand that 5 is an integer literal and you have to cast it. I also understand that if the value is not a constant then is obvious that it needs to throw that error because maybe the value reaches the limit of a short type. But why if the compiler knows I'm passing a constant that a short can hold (as in the assignment) it doesn't let it compile? I mean, what is the difference between them?
回答1:
In order to understand why the assignment type-conversion works whilst the invocation one is rejected, one has to refer to the Java Language Specification topic for both narrowing primitive conversions and the context of that conversion: assignment context and invocation context.
According to the JLS, the narrowing primitive conversion is allowed in assignment context if:
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.
... which matches your case with int
constant 5
when assigned to short a
.
No such narrowing primitive conversion is allowed in the invocation context, which explains why your call to setNum(short)
fails when passed the int
constant 5
.
But why if the compiler knows I'm passing a constant that a short can hold (as in the assignment) it doesn't let it compile? I mean, what is the difference between them?
The JLS must not have wanted to burden compilers with this additional logic. In the invocation case, the argument which is type-matched to the formal parameter is an expression - the compiler already has to determine the type, but it shouldn't need to also check if the expression's value can also safely be narrowed. In this case, being a constant, it is clear to us that it can be, but in execution context the compiler is allowed to not bother with that check, and is in-fact correct to disallow it.
It should be fairly clear that when expressions are allowed, it would be much easier for bugs to creep in where narrowing cannot be done without losing precision, so the JLS and compilers just disallow it in all cases.
The same is true in numeric context, so the declaration:
short a = 5;short b = a * 5;
... is similarly not allowed, despite being clearly comprised of constants which narrow correctly.
回答2:
When you type 5
, this is automatically an integer. I'm not sure what IDE you are using that's giving you the error, but the reason it's warning you is because you're converting a larger storage capacity value to a smaller one, which although not in your case, could result in you losing data. This is called a narrowing conversion.
Integers can hold 32 bits of data, while shorts can only hold 16 bits of data. So, for example (in reality the numbers would be much bigger), an int had a value equal to 50, and you then cast it to a short, the data would be cut to "5" because a short doesn't have a large enough memory allocation.
That code you posted won't work because when you define the short like follows:
short a = 5;
You're directly creating a short, and the number is small enough that the short can hold it. When you type "5" alone as a method argument, it's handled as an integer, and the JVM doesn't know that it's small and safe to make a short. To make the "5" suitable as an argument for the method, you need to turn it into a short using a narrowing conversion, as follows:
setNum((short) 5);
But as stated, if you don't actually know the value of the int, and you're not sure it's small enough to be turned into a short, this can create errors in your code as some of the number will be chopped off.
(Here is some Oracle documentation on this)
来源:https://stackoverflow.com/questions/39886332/why-can-i-assign-an-integer-literal-to-a-short-type-variable-but-not-to-a-short