问题
Certain functionality of the compiler puzzles me (Oracle JDK 1.7 using Eclipse).
So I've got this book that says char primitive needs to be explicitly cast to short and byte and this all makes sense due the data types' allowed ranges don't overlap.
In other words below code works (but wouldn't work without the explicit type casts):
char c = '&';
byte b = (byte)c;
short s = (short)c;
Printing b or s correctly displays the number 38, which is the numeric equivalent of (&) in Unicode.
Which brings me to my actual question. Why does the following work as well?
byte bc = '&';
short sc = '&';
System.out.println(bc); // Correctly displays number 38 on the console
System.out.println(sc); // Correctly displays number 38 on the console
Now I would certainly understand the following (which works too):
byte bt = (byte)'&';
System.out.println(bt); // Correctly displays number 38 on the console
But this no-compiler-warning char to byte (and short) "sneak conversion" doesn't seem right to me.
Can some one explain, why this is allowed?
Could the reason be in the interpretation of the '<char>'
itself, so that it doesn't actually ever get to a char primitive state but is handled as a numeric (octal or hexadecimal etc) value?
回答1:
Basically, the specification of assignment conversion specifies that
In addition, if the expression is a constant expression (§15.28) 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.
Your '&'
is precisely "a constant expression of type byte, short, char, or int".
回答2:
This is called compile-time narrowing of constants. It is described in section 5.2 of the Java Language Specification:
The compile-time narrowing of constants means that code such as:
byte theAnswer = 42;
is allowed. Without the narrowing, the fact that the integer literal 42 has type int would mean that a cast to byte would be required.
Same goes for character literals: if its value fits in a byte
, no conversion is required; if the value does not fit, you must put in a cast, or you would get a compile error.
For example, this would not compile:
byte bc = '\uff12'; // Does not compile without a cast
but this compiles fine:
byte bc = (byte)'\uff12';
回答3:
I don't know this explaination is enough or not, but this behavior is defined in the JLS. From the JLS, section 5.2:
In addition, if the expression is a constant expression (§15.28) 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.
- 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.
回答4:
Why does the following work as well?
Because '&'
is a constant expression whose value fits in byte
.
JLS 14.4.2
If a declarator has an initialization expression, the expression is evaluated and its value is assigned to the variable.
JLS 5.2
Assignment conversion occurs when the value of an expression is assigned (§15.26) to a variable: the type of the expression must be converted to the type of the variable.
....
In addition, if the expression is a constant expression (§15.28) 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.
回答5:
The expression '&' that is in your initializer for variable bc is a constant expression. The expression c that is in your initializer for variables b and s is not a constant expression. Java performs implicit narrowing conversions of primitives when the context requires it when the value is the result of a constant expression only.
来源:https://stackoverflow.com/questions/17063436/java-why-does-char-get-implicitly-cast-to-byte-and-short-primitive-when-it