In C/C++, an array is simply a contiguous chunk of raw memory addressed by pointers. In Java, an array is a dynamically created object allocated on the JVM Garbage-Collected Heap. An array holds a fixed number of values of a single specified data type (homogeneous elements):
new type[size] and cannot be altered dynamically.0 up to array.length - 1. Accessing an illegal index throws an ArrayIndexOutOfBoundsException at runtime.length (not a method).Java does not support true contiguous multi-dimensional matrices in flat physical memory. Instead, a multi-dimensional array is an "Array of Arrays":
int[] scores = new int[5]; â Stores 5 primitive integers contiguously in a single heap object.int[][] matrix = new int[3][4]; â A top-level array of length 3, where each cell stores a reference pointer to another separate array of length 4.int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[5];
jagged[2] = new int[3];
int[][] arr = @0x1000
[0]: @0x2001 | [1]: @0x2002
[10, 20] (Length: 2)
[30, 40, 50, 60] (Length: 4)
Java is strictly pass-by-value. When an array is passed as an argument to a method, a copy of the reference address is passed. Consequently:
arr[0] = 999;) modifies the caller's array directly because both references point to the same heap object.arr = new int[10];) rebinds only the local method reference and has no effect on the caller's reference.String[] args
The JVM captures arguments typed after the class name during terminal execution (java App user 8080) and populates the String[] args array. Arguments are indexed starting at args[0], and multiple arguments are space-delimited.
import java.util.Arrays;
public class ArrayToolkitDemo {
public static void main(String[] args) {
int[] numbers = { 54, 12, 89, 23, 67 };
// 1. Dual-Pivot Quicksort via Arrays.sort()
Arrays.sort(numbers);
System.out.println("Sorted Array : " + Arrays.toString(numbers));
// 2. Binary Search in O(log N) - Array MUST be sorted first!
int searchTarget = 67;
int foundIndex = Arrays.binarySearch(numbers, searchTarget);
System.out.printf("Found %d at Index : %d%n", searchTarget, foundIndex);
// 3. Array Copying & Filling
int[] clonedSlice = Arrays.copyOf(numbers, 3);
System.out.println("Cloned 3 Elements: " + Arrays.toString(clonedSlice));
// 4. Multidimensional Deep String formatting
int[][] grid = { { 1, 2 }, { 3, 4 } };
System.out.println("Deep 2D Matrix : " + Arrays.deepToString(grid));
}
}
In Java, the String class (defined in java.lang) is immutable: once a String object is instantiated on the Heap, its internal character sequence can never be altered. Any method that appears to modify a String (e.g., toUpperCase(), concat(), replace()) actually allocates and returns an entirely new String object in memory!
Why is String Immutable in Java? (Top Tier Viva Topic):
HashMap and HashSet.new String()String s = "Java";): The JVM checks the String Constant Pool (SCP) located inside the Heap. If "Java" already exists in the pool, no new object is created; the JVM simply returns a reference to the existing pooled instance.
new Keyword (String s = new String("Java");): The JVM unconditionally creates a new object on the general Heap outside the SCP, even if the identical literal already exists in the SCP.
s1 = "Java"s2 = "Java"s3 = new String("Java")
@0xPOOL_1 ["Java"]@0xHEAP_9 ["Java"]== vs. equals() vs. compareTo()== Operator: Compares reference addresses in memory. Returns true only if both references point to the exact same memory location..equals(): Compares the actual content/characters for semantic equality. Case-sensitive..equalsIgnoreCase(): Compares string contents while ignoring upper/lower case differences..compareTo(): Compares two strings lexicographically based on Unicode values. Returns 0 if equal, negative if calling string precedes argument, and positive if it follows.| Method Signature | Return Type | Description & Behavior |
|---|---|---|
length() |
int |
Returns total number of UTF-16 code units in the string. |
charAt(int index) |
char |
Returns the character at the specified 0-based index. |
substring(int start, int end) |
String |
Extracts substring from start (inclusive) to end (exclusive). |
contains(CharSequence s) |
boolean |
Returns true if the string contains the specified sequence. |
split(String regex) |
String[] |
Splits string into array of tokens around regular expression matches. |
strip() / trim() |
String |
Removes leading and trailing whitespace (strip() is Unicode-aware, Java 11+). |
replace(char old, char new) |
String |
Returns new string replacing all occurrences of old character with new. |
StringBuffer vs. StringBuilder
Because Strings are immutable, concatenating strings in a loop using += is a severe performance anti-pattern. Each iteration creates an entirely new temporary String object and discards the previous one, leading to $O(N^2)$ time complexity and aggressive heap memory churn!
Java provides two mutable companion classes that maintain a growable internal buffer (`char[]` / `byte[]`):
StringBuffer (Java 1.0): Thread-Safe & Synchronized. Every public method (append(), insert(), delete()) is synchronized with monitor locks. Safe for concurrent multi-threaded writes, but incurs significant lock acquisition overhead.
StringBuilder (Java 5): Not Thread-Safe & Non-Synchronized. Identical API to StringBuffer, but without synchronization overhead. Designed for single-threaded operations and local method buffers. Always use StringBuilder unless thread-safety across multiple threads is explicitly required!
| Characteristic | String |
StringBuffer |
StringBuilder |
|---|---|---|---|
| Mutability | Immutable | Mutable | Mutable |
| Thread-Safety | Naturally Thread-Safe | Thread-Safe (Synchronized) | Not Thread-Safe |
| Performance Speed | Slow on repeated modifications | Medium (Lock overhead) | Blazing Fast (No locks) |
| Memory Location | String Constant Pool / Heap | Heap | Heap |
| Introduction | Java 1.0 | Java 1.0 | Java 5.0 (Modern Standard) |
String.format() & Printf Specifiers
Java provides String.format() and System.out.printf() for generating structured, aligned, and localized string presentations. Format specifiers follow the syntax:
%[argument_index$][flags][width][.precision]conversion_character
%s : Formats strings or arbitrary objects.%d : Formats decimal integers.%f : Formats floating-point numbers (e.g., %.2f rounds to 2 decimal places).%10s : Right-aligns string in a field width of 10 spaces.%-10s : Left-aligns string in a field width of 10 spaces.%,d : Inserts locale-specific thousands grouping commas (e.g., 1,000,000).%n : Platform-independent newline separator (preferable to \n).
To synthesize Unit 4, we build an end-to-end Text Analytics and Matrix Transformation Engine that demonstrates: 2D Jagged array allocations, Arrays.sort() and binary search, parsing raw delimited text records, string cleaning, high-speed StringBuilder token reconstruction, and formatted table generation.
import java.util.Arrays;
/**
* DevAscent Academy â Unit 4 Capstone Project
* Demonstrates 2D Arrays, String Pool Dynamics, and StringBuilder Processing.
*/
public class TextAndMatrixEngine {
public static void main(String[] args) {
System.out.println("==================================================");
System.out.println(" DEVASCENT TEXT ANALYTICS & MATRIX PIPELINE ");
System.out.println("==================================================");
// 1. Parsing & Transforming Delimited Data via StringBuilder
String rawLog = " prod-us-101 | 240ms | OK ; prod-eu-202 | 180ms | OK ; prod-ap-303 | 920ms | TIMEOUT ";
String[] serverRecords = rawLog.trim().split("\\s*;\\s*");
System.out.println("--- 1. Parsed Server Telemetry Report ---");
System.out.printf("%-14s %-10s %-10s%n", "SERVER ID", "LATENCY", "STATUS");
System.out.println("----------------------------------------");
StringBuilder alertSummary = new StringBuilder();
for (String record : serverRecords) {
String[] tokens = record.split("\\s*\\|\\s*");
String serverId = tokens[0];
String latency = tokens[1];
String status = tokens[2];
System.out.printf("%-14s %-10s %-10s%n", serverId, latency, status);
if (!status.equalsIgnoreCase("OK")) {
alertSummary.append("[ALERT: ").append(serverId).append(" -> ").append(status).append("] ");
}
}
System.out.println("Incident Report : " + (alertSummary.length() > 0 ? alertSummary.toString() : "All nodes healthy"));
System.out.println("--------------------------------------------------");
// 2. Jagged Sensor Array: Varying Readings per Station
System.out.println("--- 2. Jagged Sensor Matrix Analysis ---");
double[][] sensorReadings = new double[3][];
sensorReadings[0] = new double[] { 23.4, 24.1 }; // Station 0: 2 readings
sensorReadings[1] = new double[] { 19.8, 20.1, 19.5, 20.8 }; // Station 1: 4 readings
sensorReadings[2] = new double[] { 31.2, 32.0, 31.8 }; // Station 2: 3 readings
for (int i = 0; i < sensorReadings.length; i++) {
double sum = 0.0;
for (double temp : sensorReadings[i]) {
sum += temp;
}
double avg = sum / sensorReadings[i].length;
System.out.printf("Station #%d (%d readings): Avg Temp = %.2f°C | Raw = %s%n",
i, sensorReadings[i].length, avg, Arrays.toString(sensorReadings[i]));
}
System.out.println("==================================================");
}
}
String s1 = "Java"; String s2 = new String("Java"); System.out.println(s1 == s2);?false. The == operator compares reference memory addresses. s1 references an object residing inside the String Constant Pool, whereas s2 was explicitly created using new, placing it in the general Heap memory outside the SCP. Since they occupy different memory addresses, s1 == s2 is false. However, s1.equals(s2) evaluates to true because their character contents are identical.
StringBuilder be preferred over String when concatenating in loops?String objects are immutable, using += inside a loop creates a new String object in every iteration and discards the old one, leading to $O(N^2)$ algorithmic time complexity and heavy garbage collection overhead. StringBuilder maintains a resizable internal buffer that appends characters in-place with $O(1)$ amortized time complexity, running orders of magnitude faster.
StringBuffer and StringBuilder?StringBuffer is thread-safe and synchronized: its public methods acquire monitor locks, making it safe for concurrent access across multiple threads, but slower due to synchronization overhead. StringBuilder is non-synchronized and not thread-safe, making it significantly faster. StringBuilder is the modern standard for single-threaded or method-local string manipulation.
int[][] arr = new int[3][];) and then instantiating each row individually with custom lengths (arr[0] = new int[2]; arr[1] = new int[5];).
arr[0] = 99;) mutates the caller's array directly. However, reassigning the parameter reference itself (arr = new int[5];) changes only the local method reference and has no effect on the caller's array.
length and length() in Java?length is a public final field (attribute) defined on array objects that returns the fixed capacity of the array (e.g., myArray.length). length() is a public method defined on the String class that returns the number of UTF-16 characters present in the string (e.g., myString.length()).
String.intern() method do?intern() method searches the String Constant Pool for a string with the exact same character content as the calling String object. If found, it returns the reference from the pool. If not found, it adds the string to the pool and returns a reference to it. This allows a heap string created via new to be deduplicated and normalized against the SCP.