Arrays & Multidimensional Arrays

15 questions found

How do you declare, initialize, and access elements of a one-dimensional array in Java?

Beginner
An array is declared with a type followed by square brackets (int[] arr), instantiated with new specifying its fixed size (new int[5]) or using an initializer literal ({1, 2, 3}), and accessed/modified via zero-based indexing (arr[0]) -- once created, an array's length is fixed and immutable for its lifetime, unlike a resizable collection like ArrayList.
int[] numbers = new int[5];  // all elements default to 0
numbers[0] = 10;
numbers[1] = 20;

int[] literal = {1, 2, 3, 4, 5};  // initializer syntax
System.out.println(literal[2]);  // prints 3
System.out.println(literal.length);  // prints 5, note: .length is a field, not a method
Real-world example A fixed-size lookup table mapping day-of-week integers (0-6) to day names is implemented as a simple String array, appropriate since the collection's size is known and fixed at compile time and never needs to grow or shrink.

Common follow-ups: Why is array.length a field access rather than a method call, unlike String's .length()?;What happens if you access an index outside the array's bounds?

Collections Framework;Java Fundamentals: Syntax Data Types & Operators

How do multidimensional arrays work in Java, and how do they differ from truly rectangular arrays in languages like C?

Intermediate
Java doesn't have true multidimensional arrays in the C sense; a 2D array (int[][]) is actually an array of arrays, where each row is an independently allocated one-dimensional array object -- this means rows can have different lengths (a "jagged" array), unlike a genuinely rectangular structure, and each row must be individually instantiated or accessed via nested indexing, with memory layout reflecting this array-of-arrays structure rather than one contiguous rectangular block.
int[][] matrix = new int[3][4];  // 3 rows, each with 4 columns (rectangular)
matrix[1][2] = 99;

int[][] jagged = new int[3][];  // 3 rows, columns not yet specified
jagged[0] = new int[2];
jagged[1] = new int[5];  // different length than row 0 -- legal, since it's an array of arrays
jagged[2] = new int[1];
Real-world example A program modeling a triangular data structure (like Pascal's triangle, where each row has one more element than the previous) uses a jagged array where each row is deliberately allocated with a different length, taking advantage of Java arrays not being required to be rectangular.

Common follow-ups: How would you iterate a jagged array safely without an IndexOutOfBoundsException from assuming uniform row length?;What's the memory/performance implication of the array-of-arrays structure versus a true contiguous 2D block?

Java Fundamentals: Syntax Data Types & Operators;Generics

How does Java implement covariant array typing, and why is this considered a design flaw that can lead to runtime ArrayStoreException?

Advanced
Java arrays are covariant, meaning Object[] arr = new String[3] is legal (a String[] reference can be assigned to an Object[] variable) since arrays retain their actual runtime component type -- but this creates a loophole where code operating on the Object[] reference can attempt to insert an incompatible type at runtime (arr[0] = Integer.valueOf(1)), which the compiler cannot catch statically and instead throws ArrayStoreException only when that specific line actually executes, illustrating why generics deliberately chose invariance instead to catch such errors at compile time.
Object[] arr = new String[3];  // legal due to covariance
arr[0] = "hello";  // fine, actual runtime type is String[]
arr[1] = Integer.valueOf(42);  // compiles fine (Object accepts Integer)... but throws ArrayStoreException at RUNTIME
Real-world example A library method accepting an Object[] parameter unknowingly receives a String[] and attempts to insert a non-String object into it, causing a production ArrayStoreException that a compile-time type system (like Java Generics' intentional invariance) would have caught much earlier during development instead.

Common follow-ups: Why did Java's generics designers choose invariance (List<String> is NOT a List<Object>) specifically to avoid this exact array pitfall?;How does the JVM implement the runtime check that throws ArrayStoreException?

Generics;Exceptions

What utility methods does java.util.Arrays provide for common array operations like sorting, searching, filling, and comparing?

Intermediate
Arrays provides static utility methods including sort() (in-place sorting, dual-pivot quicksort for primitives, TimSort for objects), binarySearch() (requires a pre-sorted array), fill() (populate all elements with one value), copyOf()/copyOfRange() (create a resized copy), equals()/deepEquals() (element-wise comparison, deepEquals needed for nested arrays), and asList() (a fixed-size List view backed by the array) -- these cover the vast majority of common array manipulation needs without hand-writing loops.
int[] nums = {5, 2, 8, 1, 9};
Arrays.sort(nums);  // {1, 2, 5, 8, 9}
int index = Arrays.binarySearch(nums, 8);  // 3

int[] copy = Arrays.copyOf(nums, 3);  // {1, 2, 5}
int[][] matrix1 = {{1,2},{3,4}};
int[][] matrix2 = {{1,2},{3,4}};
System.out.println(Arrays.equals(matrix1, matrix2));      // false -- compares references of inner arrays
System.out.println(Arrays.deepEquals(matrix1, matrix2));  // true -- recursively compares contents
Real-world example A data-processing utility sorts a large primitive int array using Arrays.sort() (leveraging its highly optimized dual-pivot quicksort implementation) rather than converting to a boxed Integer collection just to use Collections.sort(), avoiding unnecessary boxing overhead for a purely numeric workload.

Common follow-ups: Why does Arrays.equals() give a misleading false result for nested arrays, requiring deepEquals() instead?;What are the performance characteristics of Arrays.sort() for primitives versus objects?

Collections Framework;Generics

How would you efficiently copy, resize, or merge large arrays in Java, and what are the performance trade-offs between System.arraycopy(), Arrays.copyOf(), and manual loops?

Advanced
System.arraycopy() is a native method performing highly optimized bulk memory copying (often using intrinsic CPU instructions), generally the fastest option for copying array ranges; Arrays.copyOf() internally calls System.arraycopy() but adds the convenience of allocating the destination array for you, at the cost of one extra layer of indirection; a manual element-by-element loop is almost always slower than either since it can't benefit from the same low-level bulk-copy optimizations, and should generally be avoided for simple copy operations in favor of the built-in methods.
int[] source = {1, 2, 3, 4, 5};

// Fastest for a pre-allocated destination
int[] dest = new int[5];
System.arraycopy(source, 0, dest, 0, source.length);

// Convenient, internally uses System.arraycopy
int[] resized = Arrays.copyOf(source, 10);  // pads with zeros

// Merging two arrays efficiently
int[] merged = new int[source.length + dest.length];
System.arraycopy(source, 0, merged, 0, source.length);
System.arraycopy(dest, 0, merged, source.length, dest.length);
Real-world example A high-throughput data pipeline processing large numeric arrays uses System.arraycopy() directly for merging and resizing buffers, having profiled that this measurably outperforms a naive manual copy loop at the scale the pipeline operates, since arraycopy benefits from JIT intrinsics mapping directly to optimized native memory operations.

Common follow-ups: What are JIT intrinsics, and why do they make System.arraycopy() faster than equivalent hand-written Java code?;When would ArrayList's internal resizing behavior be preferable to manually managing raw array resizing?

Concurrency & Threads;Garbage Collection

How do you convert between an array and a List (ArrayList) in both directions, and what pitfalls exist with Arrays.asList()?

Intermediate
Arrays.asList(array) returns a fixed-size List backed directly by the original array (not a true resizable ArrayList -- calling add()/remove() throws UnsupportedOperationException, and mutating the array is reflected in the list view and vice versa); to get a genuinely independent, resizable list, wrap it in new ArrayList<>(Arrays.asList(array)); converting back from a List to an array uses list.toArray(new String[0]) (or the newer list.toArray(String[]::new)).
Integer[] arr = {1, 2, 3};
List<Integer> fixedView = Arrays.asList(arr);  // backed by arr, fixed-size
// fixedView.add(4);  // throws UnsupportedOperationException!

List<Integer> resizable = new ArrayList<>(Arrays.asList(arr));  // truly independent, resizable copy
resizable.add(4);  // works fine

Integer[] backToArray = resizable.toArray(new Integer[0]);
Real-world example A developer's attempt to call .add() on a list obtained directly from Arrays.asList() throws an unexpected UnsupportedOperationException in production, a common pitfall traced to Arrays.asList() returning a fixed-size view rather than a genuine resizable ArrayList.

Common follow-ups: Why does Arrays.asList() exist as a fixed-size view instead of just returning a full ArrayList directly?;What's the difference in behavior between toArray(new T[0]) and the newer toArray(T[]::new) method reference syntax?

Collections Framework;Generics

How would you implement an efficient in-place algorithm on a 2D array, such as rotating a matrix 90 degrees, while minimizing extra memory allocation?

Advanced
An in-place rotation can be achieved through a combination of transposing the matrix (swapping matrix[i][j] with matrix[j][i] across the diagonal) followed by reversing each row (or column, depending on rotation direction), avoiding the need to allocate an entirely new matrix -- this two-step decomposition is a classic technique that reduces an seemingly complex 2D transformation into two simpler, well-understood O(n²) operations performed directly on the existing array structure.
public static void rotate90Clockwise(int[][] matrix) {
    int n = matrix.length;
    // Step 1: transpose in place
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j < n; j++) {
            int temp = matrix[i][j];
            matrix[i][j] = matrix[j][i];
            matrix[j][i] = temp;
        }
    }
    // Step 2: reverse each row
    for (int[] row : matrix) {
        for (int left = 0, right = row.length - 1; left < right; left++, right--) {
            int temp = row[left];
            row[left] = row[right];
            row[right] = temp;
        }
    }
}
Real-world example An image-processing utility rotating a pixel matrix representing a small icon uses the transpose-then-reverse in-place technique to avoid allocating a second full-size matrix, meaningful for memory-constrained environments processing many images where allocation overhead would otherwise add up significantly.

Common follow-ups: What's the time and space complexity of this in-place approach compared to a naive approach allocating a new rotated matrix?;How would this algorithm need to change for a non-square (rectangular) matrix?

Diagnostics & Performance;Garbage Collection

How does Java handle array bounds checking, and what exception is thrown when accessing an invalid index?

Intermediate
Every array access in Java is automatically bounds-checked by the JVM at runtime, throwing ArrayIndexOutOfBoundsException (an unchecked RuntimeException) if the index is negative or greater than or equal to the array's length -- this automatic checking prevents the memory-corruption vulnerabilities common in languages like C that allow unchecked buffer access, at the cost of a small but generally negligible runtime overhead for each array access, though modern JIT compilers can often eliminate redundant bounds checks through optimization when they can statically prove an index is always safe.
int[] arr = {1, 2, 3};
try {
    System.out.println(arr[5]);  // throws ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid index: " + e.getMessage());
}
Real-world example A parsing routine iterating a fixed-size array with an off-by-one loop bound (using <= instead of <) is caught immediately in testing by the resulting ArrayIndexOutOfBoundsException, illustrating how Java's automatic bounds checking surfaces this class of bug loudly and immediately rather than causing silent memory corruption as it might in an unmanaged language.

Common follow-ups: How does JIT compiler bounds-check elimination work, and under what conditions can it safely skip the runtime check?;What's the performance cost of bounds checking in a very tight, performance-critical loop?

Exceptions;Diagnostics & Performance

How would you implement a custom, resizable dynamic array (similar to ArrayList's internal mechanism) from scratch using a raw Java array, including the amortized doubling growth strategy?

Advanced
A dynamic array wraps a fixed-size backing array along with a separate size counter (tracking logically used elements, distinct from the backing array's full capacity); when an add operation would exceed capacity, allocate a new backing array (conventionally double the current capacity) and copy existing elements over via System.arraycopy() -- this doubling strategy gives amortized O(1) add performance, since the expensive resize-and-copy operation happens increasingly rarely relative to the number of cheap O(1) adds, exactly matching how java.util.ArrayList is implemented internally.
public class SimpleDynamicArray<T> {
    private Object[] data = new Object[10];
    private int size = 0;

    public void add(T element) {
        if (size == data.length) {
            data = Arrays.copyOf(data, data.length * 2);  // double capacity
        }
        data[size++] = element;
    }

    @SuppressWarnings("unchecked")
    public T get(int index) {
        if (index < 0 || index >= size) throw new IndexOutOfBoundsException();
        return (T) data[index];
    }

    public int size() { return size; }
}
Real-world example An educational exercise reimplements a simplified version of ArrayList from scratch to demonstrate the amortized doubling growth strategy, showing why ArrayList's add() operation is described as amortized O(1) despite an occasional individual call actually costing O(n) during a resize event.

Common follow-ups: Why is doubling (rather than, say, adding a fixed increment) the standard growth strategy, and what's the amortized cost analysis proving O(1) add?;What would change about this implementation to support removing elements while maintaining correct amortized performance?

Collections Framework;Generics

How do you correctly iterate a 2D array using both traditional indexed for-loops and the enhanced for-each loop, and when is each approach preferable?

Intermediate
The enhanced for-each loop (for (int[] row : matrix) { for (int value : row) { ... } }) is more concise and less error-prone for simple read-only traversal, avoiding index-related bugs entirely, but doesn't give you direct access to the current index (needed if you must modify elements in place, or need to know row/column position for logic); the traditional indexed loop is required whenever you need to mutate elements, need the index for other computation, or need to iterate multiple related arrays in lockstep using a shared index.
int[][] matrix = {{1,2,3},{4,5,6}};

// for-each: simpler for read-only traversal
for (int[] row : matrix) {
    for (int value : row) {
        System.out.print(value + " ");
    }
}

// indexed: needed when mutating in place or requiring the index
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        matrix[i][j] *= 2;  // requires index-based access to mutate
    }
}
Real-world example A matrix-doubling utility uses an indexed loop specifically because it needs to write back into each cell (matrix[i][j] *= 2), whereas a separate read-only matrix-printing utility uses the simpler for-each syntax since it never needs to mutate or track explicit indices.

Common follow-ups: Why can't you assign to the for-each loop variable to modify the underlying array element?;What's the subtle bug risk of using the same variable name for both the outer and inner loop's for-each variable?

Java Fundamentals: Syntax Data Types & Operators;Generics

Showing 1–10 of 15