Creating and Using Arrays
Declaring, creating, initializing
int[] a = new int[3]; creates three elements with default values (0, or null for object arrays). int a[] also compiles but int[] a is preferred. int[] b = {1, 2, 3}; is an array initializer usable only in the declaration; later assignments need new int[]{1, 2, 3}. The size expression must be an int (a long size is a compile error), and negative sizes throw NegativeArraySizeException at runtime.
Accessing elements
length is a final field, not a method: a.length works, a.length() does not. Valid indices run 0 to length - 1; anything else throws ArrayIndexOutOfBoundsException at runtime, not at compile time.
Multidimensional arrays
int[][] m = new int[2][]; allocates the outer array only; each row is still null until separately created, giving NullPointerException on m[0][0]. Ragged arrays (rows of different lengths) are legal. int[][] m = new int[2][3] allocates all rows as well.
Traps
a.equals(b) compares identity - use Arrays.equals for content and Arrays.toString(a) for printing. Passing an array passes a copy of the reference: element changes are visible to the caller, but reassigning the parameter is not. Arrays are covariant (Object[] o = new String[1];) yet storing a wrong type throws ArrayStoreException. The enhanced for loop gives a copy of each primitive element, so assigning to the loop variable does not modify the array.
Worked example
int[] a = new int[3]; a[0] = 7; - a.length is 3 and a[3] = 1; compiles but throws ArrayIndexOutOfBoundsException when executed.