1. Contiguous Memory: Why Arrays Start at 0
An array in Java stores its elements side by side in physical RAM. The index is not an ordinal ranking, but an address offset. This is why accessing any random index takes strictly O(1) time.
Index 0 results in 0 * 4 = 0 bytes offset, pointing straight to the array start.
2. Matrices in Java: Arrays of Arrays (Jagged)
Java has no contiguous 2D grid matrix in RAM. A matrix int[][] is strictly an array containing references to independent row arrays, each able to hold a different length.
Row 0 has 2 slots. You can reassign it with new int[500] without affecting other rows.
3. String Immutability: Written in Stone
A String object in Java can NEVER be altered. Methods like .toUpperCase(), .trim(), or .replace() create a BRAND NEW object in the Heap. If unassigned, it is immediately discarded.
The quintessential beginner trap! Invoking the method without catching the return leaves s1 unchanged.
4. The String Constant Pool: == vs .equals()
The JVM saves memory by storing literal strings inside the String Constant Pool. Two literals point to the same address. However, new String() forces a separate instance. This is why you must never compare strings with ==.
Both literals share the same slot. == compares memory addresses and coincidentally yields true.
5. StringBuilder: The Mutable Text Buffer
Appending inside a loop with + ("s += i") allocates a new String per iteration, stressing the Garbage Collector. StringBuilder maintains a single internal char[] buffer that dynamically expands.
Each concatenation re-copies preceding characters into a fresh array. Cost scales quadratically.