Simple Assignment Operator =

15.26.1 Simple Assignment Operator =

A compile-time error occurs if the type of the right-hand operand cannot be converted to the type of the variable by assignment conversion (§5.2).

At run-time, the expression is evaluated in one of three ways. If the left-hand operand expression is a field access expression (§15.11) e.f ,

possibly enclosed in one or more pairs of parentheses, then: • First, the expression e is evaluated. If evaluation of e completes abruptly, the

assignment expression completes abruptly for the same reason. • Next, the right hand operand is evaluated. If evaluation of the right hand

expression completes abruptly, the assignment expression completes abruptly for the same reason.

• Then, if the field denoted by e.f is not static and the result of the evaluation of e above is null , then a NullPointerException is thrown.

• Otherwise, the variable denoted by e.f is assigned the value of the right hand operand as computed above.

If the left-hand operand is an array access expression (§15.13), possibly enclosed in one or more pairs of parentheses, then:

• First, the array reference subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason; the index subexpression (of the left-hand operand array access expression) and the right- hand operand are not evaluated and no assignment occurs.

• Otherwise, the index subexpression of the left-hand operand array access expression is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and the right-hand operand is not evaluated and no assignment occurs.

• Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

• Otherwise, if the value of the array reference subexpression is null , then no assignment occurs and a NullPointerException is thrown.

• Otherwise, the value of the array reference subexpression indeed refers to an array. If the value of the index subexpression is less than zero, or greater

EXPRESSIONS Simple Assignment Operator = 15.26.1

than or equal to the length of the array, then no assignment occurs and an ArrayIndexOutOfBoundsException is thrown.

• Otherwise, the value of the index subexpression is used to select a component of the array referred to by the value of the array reference subexpression.

This component is a variable; call its type SC . Also, let TC be the type of the left- hand operand of the assignment operator as determined at compile time. Then there are two possibilities:

◆ If TC is a primitive type, then SC is necessarily the same as TC . The value of the right-hand operand is converted to the type of the selected

array component, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the array component.

◆ If TC is a reference type, then SC may not be the same as TC , but rather a type that extends or implements TC .

Let RC

be the class of the object referred to by the value of the right-hand operand at run-time.

A Java compiler may be able to prove at compile time that the array component will be of type TC exactly (for example, TC might be final ). But if a Java compiler cannot prove at compile time that the array component will be of type TC exactly, then a check must be performed at run-time to ensure that the class RC is assignment compatible (§5.2) with the actual type SC of the array component.

This check is similar to a narrowing cast (§5.5, §15.16), except that if the check fails, an ArrayStoreException is thrown rather than a ClassCastException .

If class RC is not assignable to type SC , then no assignment occurs and an ArrayStoreException is thrown.

Otherwise, the reference value of the right-hand operand is stored into the selected array component.

Otherwise, three steps are required: • First, the left-hand operand is evaluated to produce a variable. If this evaluation

completes abruptly, then the assignment expression completes abruptly for the same reason; the right-hand operand is not evaluated and no assignment occurs.

15.26.1 Simple Assignment Operator = EXPRESSIONS

• Otherwise, the right-hand operand is evaluated. If this evaluation completes abruptly, then the assignment expression completes abruptly for the same reason and no assignment occurs.

• Otherwise, the value of the right-hand operand is converted to the type of the left- hand variable, is subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

Example 15.26.1-1. Simple Assignment To An Array Component

class ArrayReferenceThrow extends RuntimeException { } class IndexThrow extends RuntimeException { } class RightHandSideThrow extends RuntimeException { }

class IllustrateSimpleArrayAssignment { static Object[] objects = { new Object(), new Object() }; static Thread[] threads = { new Thread(), new Thread() };

static Object[] arrayThrow() {

throw new ArrayReferenceThrow();

} static int indexThrow() {

throw new IndexThrow();

} static Thread rightThrow() {

throw new RightHandSideThrow();

} static String name(Object q) {

String sq = q.getClass().getName(); int k = sq.lastIndexOf('.'); return (k < 0) ? sq : sq.substring(k+1);

static void testFour(Object[] x, int j, Object y) { String sx = x == null ? "null" : name(x[0]) + "s"; String sy = name(y); System.out.println(); try {

System.out.print(sx + "[throw]=throw => "); x[indexThrow()] = rightThrow(); System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print(sx + "[throw]=" + sy + " => "); x[indexThrow()] = y; System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print(sx + "[" + j + "]=throw => "); x[j] = rightThrow(); System.out.println("Okay!");

EXPRESSIONS Simple Assignment Operator = 15.26.1

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print(sx + "[" + j + "]=" + sy + " => "); x[j] = y; System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); }

public static void main(String[] args) { try {

System.out.print("throw[throw]=throw => "); arrayThrow()[indexThrow()] = rightThrow(); System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print("throw[throw]=Thread => "); arrayThrow()[indexThrow()] = new Thread(); System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print("throw[1]=throw => "); arrayThrow()[1] = rightThrow(); System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); } try {

System.out.print("throw[1]=Thread => "); arrayThrow()[1] = new Thread(); System.out.println("Okay!");

} catch (Throwable e) { System.out.println(name(e)); }

testFour(null, 1, new StringBuffer()); testFour(null, 1, new StringBuffer()); testFour(null, 9, new Thread()); testFour(null, 9, new Thread()); testFour(objects, 1, new StringBuffer()); testFour(objects, 1, new Thread()); testFour(objects, 9, new StringBuffer()); testFour(objects, 9, new Thread()); testFour(threads, 1, new StringBuffer()); testFour(threads, 1, new Thread()); testFour(threads, 9, new StringBuffer()); testFour(threads, 9, new Thread());

This program produces the output:

15.26.1 Simple Assignment Operator = EXPRESSIONS

throw[throw]=throw => ArrayReferenceThrow throw[throw]=Thread => ArrayReferenceThrow throw[1]=throw => ArrayReferenceThrow throw[1]=Thread => ArrayReferenceThrow

null[throw]=throw => IndexThrow null[throw]=StringBuffer => IndexThrow null[1]=throw => RightHandSideThrow null[1]=StringBuffer => NullPointerException

null[throw]=throw => IndexThrow null[throw]=StringBuffer => IndexThrow null[1]=throw => RightHandSideThrow null[1]=StringBuffer => NullPointerException

null[throw]=throw => IndexThrow null[throw]=Thread => IndexThrow null[9]=throw => RightHandSideThrow null[9]=Thread => NullPointerException

null[throw]=throw => IndexThrow null[throw]=Thread => IndexThrow null[9]=throw => RightHandSideThrow null[9]=Thread => NullPointerException

Objects[throw]=throw => IndexThrow Objects[throw]=StringBuffer => IndexThrow Objects[1]=throw => RightHandSideThrow Objects[1]=StringBuffer => Okay!

Objects[throw]=throw => IndexThrow Objects[throw]=Thread => IndexThrow Objects[1]=throw => RightHandSideThrow Objects[1]=Thread => Okay!

Objects[throw]=throw => IndexThrow Objects[throw]=StringBuffer => IndexThrow Objects[9]=throw => RightHandSideThrow Objects[9]=StringBuffer => ArrayIndexOutOfBoundsException

Objects[throw]=throw => IndexThrow Objects[throw]=Thread => IndexThrow Objects[9]=throw => RightHandSideThrow Objects[9]=Thread => ArrayIndexOutOfBoundsException

Threads[throw]=throw => IndexThrow Threads[throw]=StringBuffer => IndexThrow Threads[1]=throw => RightHandSideThrow Threads[1]=StringBuffer => ArrayStoreException

Threads[throw]=throw => IndexThrow Threads[throw]=Thread => IndexThrow Threads[1]=throw => RightHandSideThrow Threads[1]=Thread => Okay!

528 Threads[throw]=throw => IndexThrow

EXPRESSIONS Compound Assignment Operators 15.26.2

The most interesting case of the lot is the last entry in the tenth "group" of four: Threads[1]=StringBuffer => ArrayStoreException which indicates that the attempt to store a reference to a StringBuffer into an array whose

components are of type Thread throws an ArrayStoreException . The code is type- correct at compile time: the assignment has a left-hand side of type Object[] and a right- hand side of type Object . At run-time, the first actual argument to method testFour is a reference to an instance of "array of Thread " and the third actual argument is a reference to an instance of class StringBuffer .