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 two ways. If the left-hand operand expression is not an array access expression, then three steps are required:
If the left-hand operand expression is an array access expression (§15.12), then many steps are required:
null
, then no assignment occurs and a NullPointerException
is thrown.
IndexOutOfBoundsException
is thrown.
final
). But if the 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.4, §15.15), except that if the check fails, an ArrayStoreException
is thrown rather than a ClassCastException
. Therefore:
The rules for assignment to an array component are illustrated by the following example program:
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!"); } 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()); }
}
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 => IndexOutOfBoundsException
Objects[throw]=throw => IndexThrow Objects[throw]=Thread => IndexThrow Objects[9]=throw => RightHandSideThrow Objects[9]=Thread => IndexOutOfBoundsException
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!
Threads[throw]=throw => IndexThrow Threads[throw]=StringBuffer => IndexThrow Threads[9]=throw => RightHandSideThrow Threads[9]=StringBuffer => IndexOutOfBoundsException
Threads[throw]=throw => IndexThrow Threads[throw]=Thread => IndexThrow Threads[9]=throw => RightHandSideThrow Threads[9]=Thread => IndexOutOfBoundsException
The most interesting case of the lot is the one thirteenth from the end:
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
.