How does the Java cast operator work?
Is the JLS good enough?
Casting conversion is applied to the operand of a cast operator (§15.16): the type of the operand expression must be converted to the type explicitly named by the cast operator. Casting contexts allow the use of:
- an identity conversion (§5.1.1)
- a widening primitive conversion (§5.1.2)
- a narrowing primitive conversion (§5.1.3)
- a widening reference conversion (§5.1.5) optionally followed by an unchecked conversion (§5.1.9)
- a narrowing reference conversion (§5.1.6) optionally followed by an unchecked conversion
- a boxing conversion (§5.1.7)
- an unboxing conversion (§5.1.8).
Actually, maybe this part is more relevant:
The detailed rules for compile-time legality of a casting conversion of a value of compile-time reference type S to a compile-time reference type T are as follows:
- If
S is a class type:
- If T is
a class type, then either |S|
<: |T|, or |T| <:
|S|; otherwise a compile-time
error occurs. Furthermore, if there
exists a supertype X of
T, and a supertype Y of
S, such that both X and
Y are provably distinct
parameterized types (§4.5),
and that the erasures of X and
Y are the same, a compile-time
error occurs.
- If T is an interface type:
- If
S is not afinal
class (§8.1.1),
then, if there exists a supertype
X of T, and a supertype
Y of S, such that both
X and Y are provably
distinct parameterized types, and that
the erasures of X and Y
are the same, a compile-time error
occurs. Otherwise, the cast is always
legal at compile time (because even if
S does not implement T,
a subclass of S might).- If S is a
final
class (§8.1.1),
then S must implement T,
or a compile-time error occurs.
- If T
is a type variable, then this
algorithm is applied recursively,
using the upper bound of T in
place of T.- If T is
an array type, then S must be
the classObject
, or a
compile-time error occurs.- If S is
an interface type:
- If T is
an array type, then T must
implement S, or a compile-time
error occurs.
- If T is a type that is not
final
(§8.1.1),
then if there exists a supertype
X of T, and a supertype
Y of S, such that both
X and Y are provably
distinct parameterized types, and that
the erasures of X and Y
are the same, a compile-time error
occurs. Otherwise, the cast is always
legal at compile time (because even if
T does not implement S,
a subclass of T might).- If T is
a type that isfinal
,
then:
- If S is not a parameterized
type or a raw type, then T must
implement S, and the cast is
statically known to be correct, or a
compile-time error occurs.- Otherwise,
S is either a parameterized
type that is an invocation of some
generic type declaration G, or
a raw type corresponding to a generic
type declaration G. Then there
must exist a supertype X of
T, such that X is an
invocation of G, or a
compile-time error occurs.
Furthermore, if S and X
are provably distinct parameterized
types then a compile-time error
occurs.- If S is
a type variable, then this algorithm
is applied recursively, using the
upper bound of S in place of
S.- If
S is an array type SC[],
that is, an array of components of
type SC:
- If T is a
class type, then if T is not
Object
, then a
compile-time error occurs (because
Object
is the only class
type to which arrays can be assigned).
- If T
is an interface type, then a
compile-time error occurs unless
T is the type
java.io.Serializable
or
the typeCloneable
, the
only interfaces implemented by arrays.
- If T
is a type variable, then:
- If the upper
bound of T is
Object
or the type
java.io.Serializable
or
the typeCloneable
, or a
type variable that S could
legally be cast to by recursively
applying these rules, then the cast is
legal (though unchecked).- If the upper
bound of T is an array type
TC[], then a compile-time error
occurs unless the type SC[] can
be cast to TC[] by a recursive
application of these compile-time
rules for casting.- Otherwise, a
compile-time error occurs.- If T is
an array type TC[], that is, an
array of components of type TC,
then a compile-time error occurs
unless one of the following is true:
- TC and SC are the
same primitive type.- TC and
SC are reference types and type
SC can be cast to TC by
a recursive application of these
compile-time rules for casting.
Perfectly clear now, isn't it? :D
In other words, this is the best I can do without knowing more details about your problem.
Java Class.cast() vs. cast operator
I've only ever used Class.cast(Object)
to avoid warnings in "generics land". I often see methods doing things like this:
@SuppressWarnings("unchecked")
<T> T doSomething() {
Object o;
// snip
return (T) o;
}
It's often best to replace it by:
<T> T doSomething(Class<T> cls) {
Object o;
// snip
return cls.cast(o);
}
That's the only use case for Class.cast(Object)
I've ever come across.
Regarding compiler warnings: I suspect that Class.cast(Object)
isn't special to the compiler. It could be optimized when used statically (i.e. Foo.class.cast(o)
rather than cls.cast(o)
) but I've never seen anybody using it - which makes the effort of building this optimization into the compiler somewhat worthless.
What is point of type casting?
char
is an integral type in Java, and when you perform arithmetic the result is an int
(JLS-4.2.2. Integer Operations says, in part, the numerical operators, which result in a value of type int
or long
and adds that does include the additive operators +
and -
).
char c = 'A';
System.out.printf("'%c' = %d%n", c, (int) c);
int d = (c - 'A' + 'a'); // c - 65 + 97
System.out.printf("'%c' = %d%n", (char) d, d);
And I get
'A' = 65
'a' = 97
What if a cast operator is used in shift operators
The Java 8 JLS also states in §5.6.1:
5.6.1. Unary Numeric Promotion
Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:
...
- Otherwise, if the operand is of compile-time type
byte
,short
, orchar
, it is promoted to a value of typeint
by a widening primitive conversion (§5.1.2)....
Thus, if we take the following expression:
int i = ...
short s = (short) i << 2;
Will result in a compiler error:
Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i << 2;
Ideone demo
This is due to the fact that the cast binds to the first argument of the shift, not the whole expression. Here is the whole expression with explicit parenthesis:
short s = ((byte) i) << 2;
Whereas
int i = ...;
int j = (short) i << 2;
Will successfully compile.
Ideone demo
So the effective bits to use for anything < int
is the same as for int
(5
bits) since they are upcasted to int
automatically.
If you cast the result of the whole expression to, e.g. short
(short s = (short) (i << 2)
, then there is no automatism that takes place in the compiler. But Bohemian's answer gives a logical bound as to what bits of the right hand operator will effectively influence the value after the cast.
In newer JLS versions, the section has been reworded. For example, in Java 14 JLS, §5.6 we find (the section is shortened for breviety, I recommend reading the whole paragraph to get the full context):
5.6. Numeric Contexts
Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions of switch expressions.
An expression appears in a numeric arithmetic context if the expression is one of the following:
...
- An operand of a shift operator
<<
,>>
, or>>>
(§15.19). Operands of these shift operators are treated separately rather than as a group. Along
shift distance (right operand) does not promote the value being shifted (left operand) tolong
....
Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:
...
Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
...
Otherwise, none of the expressions are of type
double
,float
, orlong
. In this case, the kind of context determines how the promoted type is chosen.In a numeric arithmetic context or a numeric array context, the promoted type is
int
, and any expressions that are not of type int undergo widening primitive conversion toint
.In a numeric choice context, the following rules apply:
...
- Otherwise, the promoted type is
int
, and all the expressions that are not of typeint
undergo widening primitive conversion toint
....
Use of type cast operator within print statement
You can only cast a primitive to another primitive or an object to a type it is an instance of. For example, you can cast a String to an Object and an int into a long. If you want an int in a string, use String.format or concatenation will handle the conversion automatically:
System.out.print(String.format("The value of integer1 is %d", integer1));
or
System.out.print("The value of integer1 is " + integer1);
BTW, An important thing in Java about primitives and casting is that you can't cast boxed primitives to other boxed types. For example if you have
Integer foo = 1000;
Long bar = foo;
You'll get a ClassCastException, but
int foo = 1000;
long bar = foo;
will work fine
To do the same with boxed vesions:
Integer foo = 1000;
Long bar = foo.longValue();
Char casting in java
It's because (num%b2)
is an int
.
The type of a conditional expression is the common type by which the two operands can be represented. So, if the "true" operand is a char
but the "false" operand is an int
, the result of someCondition ? someChar : someInt
is an int
.
It's a lot clearer if you just write it as a plain old if-else statement:
if (num%b2 >= 10) {
result.append((char)('A'+((num%b2)-10)));
} else {
result.append(num%b2);
}
Related Topics
Variable Naming Conventions in Java
Recursively List All Files Within a Directory Using Nio.File.Directorystream;
Sorting Strings That Contains Number in Java
Calling a @Bean Annotated Method in Spring Java Configuration
Java: Convert String to Timestamp
How to Parse Month Full Form String Using Dateformat in Java
Java Swing; Two Classes, Where to Put If Statements and New Actionlisteners
Calling Superclass from a Subclass Constructor in Java
How to Correctly Use Custom Renderers to Paint Specific Cells in a Jtable
Simpledateformat Parse Loses Timezone
Java Ternary Without Assignment
Java Sax Parser Split Calls to Characters()
Rounding a Double to Turn It into an Int (Java)