Assignment conversion occurs when the value of an expression is assigned (§15.25) to a variable: the type of the expression must be converted to the type of the variable. Assignment contexts allow the use of an identity conversion (§5.1.1), a widening primitive conversion (§5.1.2), or a widening reference conversion (§5.1.4). In addition, a narrowing primitive conversion may be used if all of the following conditions are satisfied:
int
.
byte
, short
, or char
.
If the type of the expression cannot be converted to the type of the variable by a conversion permitted in an assignment context, then a compile-time error occurs.
If the type of an expression can be converted to the type a variable by assignment conversion, we say the expression (or its value) is assignable to the variable or, equivalently, that the type of the expression is assignment compatible with the type of the variable.
An assignment conversion never causes an exception. (Note, however, that an assignment may result in an exception in a special case involving array elements -see §10.10 and §15.25.1.)
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:
byte theAnswer = (byte)42; // cast is permitted but not required
A value of primitive type must not be assigned to a variable of reference type; an attempt to do so will result in a compile-time error. A value of type boolean
can be assigned only to a variable of type boolean
.
The following test program contains examples of assignment conversion of primitive values:
class Test { public static void main(String[] args) { short s = 12; // narrow 12 to short float f = s; // widen short to float System.out.println("f=" + f); char c = '\u0123'; long l = c; // widen char to long System.out.println("l=0x" + Long.toString(l,16)); f = 1.23f; double d = f; // widen float to double System.out.println("d=" + d); } }
It produces the following output:
f=12.0 i=0x123 d=1.2300000190734863
The following test, however, produces compile-time errors:
class Test { public static void main(String[] args) { short s = 123; char c = s; // error: would require cast s = c; // error: would require cast } }
because not all short
values are char
values, and neither are all char
values
short
values.
A value of reference type must not be assigned to a variable of primitive type; an attempt to do so will result in a compile-time error.
A value of the null type (the null reference is the only such value) may be assigned to any reference type, resulting in a null reference of that type.
Here is a sample program illustrating assignments of references:
public class Point { int x, y; }
public class Point3D extends Point { int z; }
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable { int color; public void setColor(int color) { this.color = color; } }
class Test { public static void main(String[] args) { // Assignments to variables of class type: Point p = new Point(); p = new Point3D(); // ok: because Point3d is a // subclass of Point Point3D p3d = p; // error: will require a cast because a // Point might not be a Point3D // (even though it is, dynamically, // in this example.) // Assignments to variables of type Object: Object o = p; // ok: any object to Object int[] a = new int[3]; Object o2 = a; // ok: an array to Object
// Assignments to variables of interface type: ColoredPoint cp = new ColoredPoint(); Colorable c = cp; // ok: ColoredPoint implements // Colorable
// Assignments to variables of array type: byte[] b = new byte[4]; a = b; // error: these are not arrays // of the same primitive type Point3D[] p3da = new Point3D[3]; Point[] pa = p3da; // ok: since we can assign a // Point3D to a Point p3da = pa; // error: (cast needed) since a Point // can't be assigned to a Point3D
}
}
Assignment of a value of compile-time reference type S (source) to a variable of compile-time reference type T (target) is checked as follows:
Object
, or a compile-time error occurs.
[]
, that is, an array of components of type SC:
Object
, or a compile-time error occurs.
Cloneable
, the only interface implemented by arrays.
[]
, that is, an array of components of type TC, then a compile-time error occurs unless one of the following is true:
See §8 for the detailed specifications for classes, §9 for interfaces, and §10 for arrays.
The following test program illustrates assignment conversions on reference values, but fails to compile because it violates the preceding rules, as described in its comments. This example should be compared to the preceding one.
public class Point { int x, y; }
public interface Colorable { void setColor(int color); }
public class ColoredPoint extends Point implements Colorable { int color; public void setColor(int color) { this.color = color; } }
class Test { public static void main(String[] args) {
Point p = new Point();
ColoredPoint cp = new ColoredPoint(); // Okay because ColoredPoint is a subclass of Point: p = cp;
// Okay because ColoredPoint implements Colorable: Colorable c = cp;
// The following cause compile-time errors because // we cannot be sure they will succeed, depending on // the run-time type of p; a run-time check will be // necessary for the needed narrowing conversion and // must be indicated by including a cast: cp = p; // p might be neither a ColoredPoint // nor a subclass of ColoredPoint c = p; // p might not implement Colorable
}
}
Here is another example involving assignment of array objects:
class Point { int x, y; }
class ColoredPoint extends Point { int color; }
class Test { public static void main(String[] args) { long[] veclong = new long[100]; Object o = veclong; // okay Long l = veclong; // compile-time error short[] vecshort = veclong; // compile-time error Point[] pvec = new Point[100]; ColoredPoint[] cpvec = new ColoredPoint[100]; pvec = cpvec; // okay pvec[0] = new Point(); // okay at compile time, // but would throw an // exception at run time cpvec = pvec; // compile-time error } }
veclong
cannot be assigned to a Long
variable, because Long
is a class type (§20.8) other than Object
. An array can be assigned only to a variable of a compatible array type, or to a variable of type Object
.
veclong
cannot be assigned to vecshort
, because they are arrays of primitive type, and short
and long
are not the same primitive type.
cpvec
can be assigned to pvec
,
because any reference that could be the value of an expression of type ColoredPoint
can be the value of a variable of type Point
. The subsequent assignment of the new Point
to a component of pvec
then would throw an ArrayStoreException
(if the program were otherwise corrected so that it could be compiled), because a ColoredPoint
array can't have an instance of Point
as the value of a component.
pvec
cannot be assigned to cpvec
,
because not every reference that could be the value of an expression of type ColoredPoint
can correctly be the value of a variable of type Point
. If the value of pvec
at run time were a reference to an instance of Point[]
, and the assignment to cpvec
were allowed, a simple reference to a component of cpvec
, say, cpvec[0]
, could return a Point
, and a Point
is not a ColoredPoint
. Thus to allow such an assignment would allow a violation of the type system. A cast may be used (§5.4, §15.15) to ensure that pvec
references a ColoredPoint[]
:
cpvec = (ColoredPoint[])pvec; // okay, but may throw an // exception at run time