5.2 Assignment Conversion

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:

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:

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 } }

In this example:


		cpvec = (ColoredPoint[])pvec;										// okay, but may throw an
												// exception at run time