What is a Java Array?
An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created, and after creation, its length is fixed.
Each item in an array is called an element, and each element is accessed by its numerical index. Indexing begins at 0. For example, the 5th element of an array would be at index 4.
In Java, arrays are objects. This means they are created on the heap memory, and the variable you declare holds a reference to the array object. Because they are objects, they can be manipulated like other objects (e.g., passed to methods).
Key Properties:
- Fixed Size: You cannot change the size of an array after it's created.
- Homogeneous Data: All elements must be of the same data type (e.g., all `int` or all `String`).
- Zero-Based Indexing: The first element is at index `0`, and the last is at `length - 1`.
Memory Representation of Arrays
Understanding how arrays store values in memory is crucial for efficient programming. In Java, arrays are stored in contiguous memory locations, which allows for fast access to elements using their index.
Visualizing Array Storage
Let's visualize how an integer array is stored in memory:
When you declare an array variable, it stores a reference to the array object in memory. The array object itself contains the actual data elements in contiguous memory locations.
Memory Layout
The array variable at address 0x1000 contains a reference (0x2000) to the actual array data. Each element occupies 4 bytes (for an int) in contiguous memory locations. This contiguous storage allows for O(1) access time to any element using its index.
When you access an element with numbers[2], Java calculates the memory address as 0x2000 + (2 × 4) = 0x2008 and retrieves the value at that location.
Two-Step Process
Creating an array is a two-step process: first, you declare a variable that will hold the array reference, and second, you use the `new` operator to allocate memory for the array object itself.
Step 1: Declaration
This tells the compiler that the variable will refer to an array of a certain type.
// Preferred style
dataType[] arrayRefVar;
// C/C++ style, also works in Java
dataType arrayRefVar[];
Example: `int[] myNumbers;` or `String[] names;`
Step 2: Instantiation
This creates the array object in memory with a specified size.
arrayRefVar = new dataType[arraySize];
Example: `myNumbers = new int[10];` creates an array that can hold 10 integers.
Combining Declaration and Instantiation
int[] myNumbers = new int[10]; // An array for 10 integers
String[] names = new String[5]; // An array for 5 String objects
Default Values: When an array is created, its elements are automatically assigned default values:
- Numeric types (`int`, `double`, etc.): `0` or `0.0`
- `boolean`: `false`
- Object types (`String`, etc.): `null`
Populating and Reading Elements
You can assign values to individual elements using their index, enclosed in square brackets `[]`.
public class InitializeAccess {
public static void main(String[] args) {
int[] scores = new int[4];
scores[0] = 95;
scores[1] = 88;
scores[2] = 76;
scores[3] = 100;
// Accessing an element
System.out.println("The first score is: " + scores[0]);
// Trying to access an invalid index will cause an error
// System.out.println(scores[4]); // Throws ArrayIndexOutOfBoundsException
}
}
Array Literal Initialization
You can create and initialize an array in a single step using an array literal. The size is automatically determined by the number of elements.
public class ArrayLiteral {
public static void main(String[] args) {
// The array size is 3
String[] names = {"Alice", "Bob", "Charlie"};
System.out.println("Second name: " + names[1]);
System.out.println("Array length: " + names.length);
}
}
Iterating with a Standard `for` Loop
A standard `for` loop is ideal when you need to know the index of the element you are processing. The `length` field (not a method!) of an array tells you how many elements it can hold.
public class ProcessArray {
public static void main(String[] args) {
double[] prices = {19.99, 5.50, 12.75, 99.95};
// Find the sum of all prices
double total = 0;
for (int i = 0; i < prices.length; i++) {
total += prices[i];
}
System.out.println("Total price: $" + total);
// Find the most expensive item
double maxPrice = prices[0];
for (int i = 1; i < prices.length; i++) {
if (prices[i] > maxPrice) {
maxPrice = prices[i];
}
}
System.out.println("Highest price: $" + maxPrice);
}
}
Enhanced for-loop
JDK 1.5 introduced a more concise way to loop through all the elements of an array: the enhanced for-loop, or for-each loop.
This loop is preferred when you only need to read elements and don't need to know their index.
public class ForEachLoop {
public static void main(String[] args) {
String[] fruits = {"Apple", "Banana", "Cherry"};
// Print all the array elements
System.out.println("My favorite fruits:");
for (String fruit : fruits) {
System.out.println("- " + fruit);
}
}
}
Important: You cannot use a for-each loop to modify the array's elements, as the loop variable (`fruit` in the example) is a copy of the value, not a reference to the array slot.
Arrays of Arrays
Multidimensional arrays are simply arrays whose elements are other arrays. The most common type is a two-dimensional (2D) array, which is often used to represent tables or matrices.
Declaring and Creating a 2D Array
// Declares a 2D array of integers
int[][] matrix;
// Creates a 3x4 matrix (3 rows, 4 columns)
matrix = new int[3][4];
Initializing a 2D Array
public class MultiArray {
public static void main(String[] args) {
// Initializing with a literal
int[][] matrix = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// Accessing an element: [row][column]
System.out.println("Element at row 1, column 2: " + matrix[1][2]); // Outputs 7
}
}
Processing a 2D Array
You typically use nested `for` loops to iterate through a 2D array.
public class ProcessMultiArray {
public static void main(String[] args) {
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Iterate through all elements
for (int i = 0; i < matrix.length; i++) { // Outer loop for rows
for (int j = 0; j < matrix[i].length; j++) { // Inner loop for columns
System.out.print(matrix[i][j] + "\t");
}
System.out.println(); // New line after each row
}
}
}
Arrays as Method Parameters
Arrays are passed to methods by reference. This means the method receives a reference to the original array, not a copy. Any changes made to the array inside the method will permanently affect the original array.
public class PassArrayToMethod {
// Method to print an array
public static void printArray(int[] arr) {
for (int x : arr) {
System.out.print(x + " ");
}
System.out.println();
}
// Method that modifies the array
public static void scaleArray(int[] arr, int factor) {
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i] * factor;
}
}
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40};
System.out.print("Original array: ");
printArray(numbers);
scaleArray(numbers, 2); // Scale the array by a factor of 2
System.out.print("Array after scaling: ");
printArray(numbers); // The original array is modified
}
}
Arrays as Return Values
A method can return an array. The return type of the method must be declared as an array type (e.g., `int[]`). This is useful for methods that generate or process data and need to return a collection of values.
public class ReturnArrayFromMethod {
// This method returns a new array containing the first n prime numbers
public static int[] getFirstNPrimes(int n) {
int[] primes = new int[n];
int num = 2;
int count = 0;
while (count < n) {
if (isPrime(num)) {
primes[count] = num;
count++;
}
num++;
}
return primes;
}
// Helper method to check for primality
public static boolean isPrime(int num) {
if (num <= 1) return false;
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) return false;
}
return true;
}
public static void main(String[] args) {
int[] firstFivePrimes = getFirstNPrimes(5);
System.out.println("First 5 prime numbers:");
for (int prime : firstFivePrimes) {
System.out.print(prime + " "); // 2 3 5 7 11
}
}
}
Built-in Utility Functions
Java provides a very useful helper class, `java.util.Arrays`, which contains various static methods for manipulating arrays (such as sorting and searching). You must import it to use: `import java.util.Arrays;`
Arrays.toString()
A convenient way to get a string representation of an array's contents. It's much better than writing your own loop for printing.
import java.util.Arrays;
public class ArraysToString {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40};
System.out.println(numbers); // Prints something like [I@1b6d3586
System.out.println(Arrays.toString(numbers)); // Prints [10, 20, 30, 40]
}
}
Arrays.sort()
Sorts the elements of an array into ascending order. It uses a highly optimized, dual-pivot quicksort algorithm for primitives and Timsort for objects.
import java.util.Arrays;
public class ArraysSort {
public static void main(String[] args) {
int[] numbers = {40, 10, 30, 20};
System.out.println("Before sort: " + Arrays.toString(numbers));
Arrays.sort(numbers);
System.out.println("After sort: " + Arrays.toString(numbers));
}
}
Arrays.binarySearch()
Searches for a specified value in a sorted array using the binary search algorithm. This is very fast (O(log n)) but requires the array to be sorted first. It returns the index of the element if found, or a negative value if not found.
import java.util.Arrays;
public class ArraysBinarySearch {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50};
int index = Arrays.binarySearch(numbers, 30);
System.out.println("Index of 30 is: " + index); // 2
int notFoundIndex = Arrays.binarySearch(numbers, 35);
System.out.println("Index of 35 is: " + notFoundIndex); // A negative number
}
}
Arrays.fill()
Assigns the specified value to each element of the array. Useful for initialization. You can fill the entire array or a specific range of elements.
import java.util.Arrays;
public class ArraysFill {
public static void main(String[] args) {
int[] data = new int[5];
Arrays.fill(data, -1); // Fill the entire array with -1
System.out.println(Arrays.toString(data)); // [-1, -1, -1, -1, -1]
// Fill a specific range (from index 1 to 3, exclusive of 3)
Arrays.fill(data, 1, 3, 99);
System.out.println(Arrays.toString(data)); // [-1, 99, 99, -1, -1]
double[] prices = new double[3];
Arrays.fill(prices, 9.99);
System.out.println(Arrays.toString(prices)); // [9.99, 9.99, 9.99]
}
}
Arrays.equals()
Returns `true` if two arrays are equal in size and their corresponding elements are equal. It's the correct way to compare array contents, as the `==` operator only checks if they are the same object in memory.
import java.util.Arrays;
public class ArraysEquals {
public static void main(String[] args) {
int[] a = {1, 2, 3};
int[] b = {1, 2, 3};
int[] c = a;
System.out.println(a == b); // false (different objects)
System.out.println(a == c); // true (same object reference)
System.out.println(Arrays.equals(a, b)); // true (same contents)
// For multidimensional arrays, use deepEquals()
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
System.out.println(Arrays.equals(matrix1, matrix2)); // false (compares references)
System.out.println(Arrays.deepEquals(matrix1, matrix2)); // true (compares contents)
}
}
Arrays.compare()
Compares two arrays lexicographically (element by element). It returns:
- A negative integer if the first array is lexicographically less than the second
- Zero if the arrays are equal
- A positive integer if the first array is lexicographically greater than the second
import java.util.Arrays;
public class ArraysCompare {
public static void main(String[] args) {
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 4};
int[] arr3 = {1, 2, 3};
System.out.println(Arrays.compare(arr1, arr2)); // Negative (arr1 < arr2)
System.out.println(Arrays.compare(arr2, arr1)); // Positive (arr2 > arr1)
System.out.println(Arrays.compare(arr1, arr3)); // 0 (arr1 == arr3)
// For multidimensional arrays, use compare() on each dimension or deepEquals()
int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 5}};
System.out.println(Arrays.compare(matrix1, matrix2)); // Negative (matrix1 < matrix2)
}
}
Arrays.copyOf() and Arrays.copyOfRange()
Creates a new array that is a copy of the original array. `copyOf()` copies the entire array or truncates/pads it to the specified length. `copyOfRange()` copies a specific range of elements.
import java.util.Arrays;
public class ArraysCopy {
public static void main(String[] args) {
int[] original = {1, 2, 3, 4, 5};
// Copy entire array
int[] copy1 = Arrays.copyOf(original, original.length);
System.out.println(Arrays.toString(copy1)); // [1, 2, 3, 4, 5]
// Copy with new length (padded with zeros if longer)
int[] copy2 = Arrays.copyOf(original, 7);
System.out.println(Arrays.toString(copy2)); // [1, 2, 3, 4, 5, 0, 0]
// Copy with truncation
int[] copy3 = Arrays.copyOf(original, 3);
System.out.println(Arrays.toString(copy3)); // [1, 2, 3]
// Copy a range of elements (from index 1 to 4, exclusive of 4)
int[] copy4 = Arrays.copyOfRange(original, 1, 4);
System.out.println(Arrays.toString(copy4)); // [2, 3, 4]
}
}
Test Your Skills
- Write a program to find the average of an array of numbers.
- Write a program to check if an array contains a specific value (without using `java.util.Arrays`).
- Write a program to find the index of an array element.
- Write a program to remove a specific element from an array (by creating a new, smaller array).
- Write a program to find the sum of the diagonals of a square 2D matrix.
🏆 Challenge: Array Analyzer
Create a program that analyzes an array of integers provided by the user. The program should use `java.util.Arrays` methods where applicable and display the following:
- The original array.
- The sorted array.
- The minimum and maximum values.
- Ask the user for a number and check if it exists in the array (using `binarySearch`).
import java.util.Arrays;
import java.util.Scanner;
public class ArrayAnalyzer {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("--- Array Analyzer ---");
System.out.print("Enter numbers separated by spaces: ");
String line = scanner.nextLine();
String[] numberStrings = line.split(" ");
int[] numbers = new int[numberStrings.length];
for (int i = 0; i < numberStrings.length; i++) {
numbers[i] = Integer.parseInt(numberStrings[i]);
}
// 1. Original array
System.out.println("\nOriginal Array: " + Arrays.toString(numbers));
// 2. Sorted array
int[] sortedNumbers = Arrays.copyOf(numbers, numbers.length); // Create a copy to sort
Arrays.sort(sortedNumbers);
System.out.println("Sorted Array: " + Arrays.toString(sortedNumbers));
// 3. Min and Max
int min = sortedNumbers[0];
int max = sortedNumbers[sortedNumbers.length - 1];
System.out.println("Minimum value: " + min);
System.out.println("Maximum value: " + max);
// 4. Binary Search
System.out.print("\nEnter a number to search for: ");
int target = scanner.nextInt();
int index = Arrays.binarySearch(sortedNumbers, target);
if (index >= 0) {
System.out.println("Found " + target + " at index " + index + " in the sorted array.");
} else {
System.out.println(target + " was not found in the array.");
}
scanner.close();
}
}