CHAPTER 5
Thou art not for the fashion of these times,
Where none will sweat but for promotion.
William Shakespeare, As You Like It, Act II, scene iii
Every Java expression has a type that can be deduced from the structure of the
expression and the types of the literals, variables, and methods mentioned in the
expression. It is possible, however, to write an expression in a context where the
type of the expression is not appropriate. In some cases, this leads to an error at
compile time; for example, if the expression in an if
statement (§14.8) has any
type other than boolean
, a compile-time error occurs. In other cases, the context
may be able to accept a type that is related to the type of the expression; as a convenience, rather than requiring the programmer to indicate a type conversion
explicitly, the Java language performs an implicit conversion from the type of the
expression to a type acceptable for its surrounding context.
A specific conversion from type S to type T allows an expression of type S to be treated at compile time as if it had type T instead. In some cases this will require a corresponding action at run time to check the validity of the conversion or to translate the run-time value of the expression into a form appropriate for the new type T. For example:
Object
(§20.1) to type Thread
(§20.20) requires a run-time check to make sure that the run-time value is actually an instance of class Thread
or one of its subclasses; if it is not, an exception is thrown.
Thread
to type Object
requires no run-time action; Thread
is a subclass of Object
, so any reference produced by an expression of type Thread
is a valid reference value of type Object
.
int
to type long
requires run-time sign-extension of a 32-bit integer value to the 64-bit long
representation. No information is lost.
double
to type long
requires a nontrivial translation from a 64-bit floating-point value to the 64-bit integer representation. Depending on the actual run-time value, information may be lost.
In every conversion context, only certain specific conversions are permitted. The specific conversions that are possible in Java are grouped for convenience of description into several broad categories:
There are five conversion contexts in which conversion of Java expressions may occur. Each context allows conversions in some of the categories named above but not others. The term "conversion" is also used to describe the process of choosing a specific conversion for such a context. For example, we say that an expression that is an actual argument in a method invocation is subject to "method invocation conversion," meaning that a specific conversion will be implicitly chosen for that expression according to the rules for the method invocation argument context.
One conversion context is the operand of a numeric operator such as +
or *
. The conversion process for such operands is called numeric promotion. Promotion is special in that, in the case of binary operators, the conversion chosen for one operand may depend in part on the type of the other operand expression.
This chapter first describes the six categories of conversions (§5.1), including the special conversions to String
allowed for the string concatenation operator +
. Then the five conversion contexts are described:
String
.
Here are some examples of the various contexts for conversion:
class Test { public static void main(String[] args) { // Casting conversion (§5.4) of a float literal to // type int. Without the cast operator, this would // be a compile-time error, because this is a // narrowing conversion (§5.1.3): int i = (int)12.5f;
// String conversion (§5.4) of i's int value: System.out.println("(int)12.5f==" + i);
// Assignment conversion (§5.2) of i's value to type // float. This is a widening conversion (§5.1.2): float f = i;
// String conversion of f's float value: System.out.println("after float widening: " + f);
// Numeric promotion (§5.6) of i's value to type // float. This is a binary numeric promotion. // After promotion, the operation is float*float: System.out.print(f); f = f * i;
// Two string conversions of i and f: System.out.println("*" + i + "==" + f);
// Method invocation conversion (§5.3) of f's value // to type double, needed because the method Math.sin // accepts only a double argument: double d = Math.sin(f);
// Two string conversions of f and d: System.out.println("Math.sin(" + f + ")==" + d);
}
}
(int)12.5f==12 after float widening: 12.0 12.0*12==144.0 Math.sin(144.0)==-0.49102159389846934