Arrays and ArrayList in Java: From Basics to Implementation

Learn what arrays are and why we need them, how memory management works in Java (stack vs heap), how to declare, initialize, and manipulate arrays with input/output, explore 2D arrays and jagged arrays, understand ArrayList as a dynamic alternative to fixed-size arrays, and solve practical problems like finding max, reversing, and swapping using the two-pointer technique.

Why Arrays and What They Are

Problem: Storing Multiple Values Without Arrays

Without arrays, storing multiple values requires declaring separate variables for each item (e.g., int roleNumber1, int roleNumber2, etc.), which becomes impractical for large datasets. Arrays solve this by providing a single data structure to hold a collection of the same data type.

Definition of an Array

An array is a collection of data types (primitives or objects) of the same type stored together. You cannot mix data types in a single array—an integer array contains only integers, a string array contains only strings.

Array Syntax in Java

Arrays are declared with square brackets after the data type (e.g., int[] roleNumbers). The reference variable points to an array object. You can initialize with a size (new int[5]) or directly with values (new int[]{23, 12, 45, 32, 15}).

Memory Management and Internal Workings

Stack vs Heap: Declaration and Initialization

Declaration (int arr;) happens at compile time and creates a reference variable in stack memory. Initialization (arr = new int[5];) happens at runtime and creates the actual array object in heap memory. This is called dynamic memory allocation.

Continuous vs Non-Continuous Memory in Java

In C++, arrays occupy continuous memory blocks. In Java, heap objects are not guaranteed to be continuous (per Java Language Specification). The JVM manages memory allocation, so array elements may be scattered across different heap locations.

Default Values in Arrays

When an integer array is created, all elements default to 0. When a string (object) array is created, all elements default to null—a special literal value representing no object reference. Null can only be assigned to reference types, not primitives.

Object Arrays vs Primitive Arrays

Primitive arrays (int, boolean, float) store values directly in stack memory. Object arrays (String, custom classes) store reference variables in the array that point to objects scattered throughout heap memory. Each element of an object array is itself a reference variable.

Array Indexing and Access

Zero-Based Indexing

Array indices start at 0, not 1. For an array of size 5, valid indices are 0, 1, 2, 3, 4. The last valid index is always size minus 1. Accessing an invalid index (e.g., arr[5] on a size-5 array) throws an ArrayIndexOutOfBoundsException.

Reading and Modifying Array Elements

Access elements using arr[index]. Reading: int value = arr[2] retrieves the element at index 2. Modifying: arr[3] = 99 changes the element at index 3. Arrays are mutable—changes to array elements persist because the reference points to the same heap object.

Input and Output with Arrays

Using for Loop for Input

To fill an array with user input, use a for loop from index 0 to array.length-1. Each iteration reads one value using Scanner and stores it at arr[i]. The array.length property gives the array size without hardcoding.

Three Ways to Print Arrays

1) Manual for loop printing each element. 2) Enhanced for-each loop: for(int num : arr) print(num). 3) Arrays.toString(arr) converts array to formatted string with brackets and commas, internally using StringBuilder.

Two-Dimensional Arrays (2D Arrays)

2D Array Syntax and Structure

2D arrays use two square brackets: int[][] arr = new int[3][3]. The first number specifies rows (mandatory), the second specifies columns (optional). Internally, a 2D array is an array of arrays—each row is itself an array object stored separately in heap memory.

Jagged Arrays: Variable Column Sizes

Column size is not mandatory because each row is an independent array object. Rows can have different lengths: int[][] arr = new int[3][] allows the first row to have 3 elements, second row 2 elements, third row 4 elements. This is called a jagged array.

Accessing 2D Array Elements

Use two indices: arr[row][column]. arr[0] returns the entire first row (an array). arr[0][2] returns the element at row 0, column 2. arr.length gives number of rows. arr[i].length gives number of columns in row i.

Input for 2D Arrays with Nested Loops

Use nested for loops: outer loop iterates rows, inner loop iterates columns. For each row[i], the inner loop runs arr[i].length times to handle variable column sizes. Read input with arr[row][col] = scanner.nextInt().

Output for 2D Arrays

Use nested loops to print each element, adding a newline after each row. Alternatively, use enhanced for loop: for(int[] row : arr) print(Arrays.toString(row)) to print each row as a formatted string.

Arrays in Functions and Mutability

Passing Arrays to Functions

Java uses call-by-value, but when passing an array, a copy of the reference is passed. Both the original and copied reference point to the same heap object. Changes made inside the function affect the original array—arrays are mutable.

Mutable vs Immutable Behavior

Arrays are mutable: modifying arr[0] inside a function changes the original. Strings are immutable: reassigning a string inside a function does not affect the original. This distinction matters when designing functions that modify data structures.

ArrayList: Dynamic Arrays

Why ArrayList: Fixed Size Problem

Arrays require a fixed size at creation. If you don't know how many elements you'll need, ArrayList is the solution. ArrayList automatically grows as you add elements, eliminating the need to pre-declare size.

ArrayList Syntax and Declaration

ArrayList is part of Java's Collection Framework (java.util package). Syntax: List<Integer> list = new ArrayList<Integer>() or ArrayList<Integer> list = new ArrayList<>(). The generic type (e.g., Integer) specifies what data type can be stored. Primitives cannot be used directly; use wrapper classes (Integer, String, etc.).

ArrayList Methods: Add, Get, Set, Remove

list.add(value) appends an element. list.get(index) retrieves element at index. list.set(index, value) updates element at index. list.remove(index) removes element at index. list.contains(value) checks if value exists. list.size() returns number of elements.

ArrayList Internal Growth Mechanism

ArrayList maintains an internal fixed-size array. When capacity is reached, a new larger array is created (using a growth formula), old elements are copied, and the old array is discarded. This happens automatically, making ArrayList appear unlimited in size.

Iterating ArrayList with for Loop and Enhanced for

Use traditional for: for(int i=0; i<list.size(); i++) list.get(i). Or enhanced for: for(Integer num : list) print(num). Both work; enhanced for is cleaner when you don't need the index.

Multi-Dimensional ArrayList

ArrayList<ArrayList<Integer>> creates a 2D ArrayList. Each element is itself an ArrayList. Must initialize inner lists explicitly: list.add(new ArrayList<>()). Then access with list.get(i).add(value) or list.get(i).get(j).

Practical Array Problems

Swap Function

Swap two elements at indices i and j using a temporary variable: temp = arr[i]; arr[i] = arr[j]; arr[j] = temp. Useful for sorting and reversing operations. Changes persist because arrays are mutable.

Find Maximum Element

Assume first element is max. Iterate through array comparing each element with current max. If element is greater, update max. Return max after loop. Time complexity: O(n). Can be extended to find max in a range by specifying start and end indices.

Reverse Array Using Two-Pointer Technique

Use two pointers: start at index 0, end at index length-1. Swap elements at start and end. Move start forward, end backward. Stop when start >= end. This efficiently reverses the array in O(n) time with O(1) space.

Key Concepts Summary

New Keyword

The 'new' keyword creates an object in heap memory at runtime. For arrays: new int[5] allocates space for 5 integers in heap. Without 'new', only the reference variable is created (compile time); the actual object doesn't exist.

Null: Special Literal for Reference Types

Null is a special literal (not a type or object) representing 'no object reference'. By default, all reference variables point to null. Can be assigned to any reference type (String, arrays, objects) but not to primitives. Similar to 'None' in Python.

Edge Cases to Handle

When writing array functions, check for null arrays, empty arrays (length 0), and invalid indices. Return sentinel values (e.g., -1) or throw exceptions for invalid inputs. Proper edge case handling prevents runtime errors.

Notable quotes

Array is basically a collection of your data types, it can either be primitives or objects. — Kunal Kushwaha
Arrays are mutable in Java. Strings are immutable in Java. — Kunal Kushwaha
In Java, there is no concept of pointers. You cannot get the address or anything. — Kunal Kushwaha

Action items

  • Create a program to take 5 integers as input into an array and print them using all three methods: manual for loop, enhanced for loop, and Arrays.toString().
  • Write a function to find the maximum element in an array and test it with different inputs including edge cases (empty array, single element, negative numbers).
  • Implement the swap function and use it to reverse an array using the two-pointer technique.
  • Create a 2D array program that takes 3x3 matrix input and prints it in matrix format with proper row and column alignment.
  • Write a program using ArrayList to store user-input integers until the user enters -1, then print all elements and calculate the average.
  • Implement a multi-dimensional ArrayList (ArrayList of ArrayList) to store and print a 3x3 matrix of integers.
  • Create a function that finds the maximum element in a specified range of an array (between start and end indices).
  • Write a program to demonstrate the difference between passing arrays to functions (mutable behavior) vs passing primitives (immutable behavior).
Kunal Kushwaha
1 hr 46 min video
3 min read
Arrays and ArrayList in Java: From Basics to Implementation
You just saved 1 hr 43 min.
The big takeaway
Learn what arrays are and why we need them, how memory management works in Java (stack vs heap), how to declare, initialize, and manipulate arrays with input/output, explore 2D arrays and jagged arrays, understand ArrayList as a dynamic alternative to fixed-size arrays, and solve practical problems like finding max, reversing, and swapping using the two-pointer technique.
Why Arrays and What They Are
Problem: Storing Multiple Values Without Arrays
Without arrays, storing multiple values requires declaring separate variables for each item (e.g., int roleNumber1, int roleNumber2, etc.), which becomes impractical for large datasets. Arrays solve this by providing a single data structure to hold a collection of the same data type.
Definition of an Array
An array is a collection of data types (primitives or objects) of the same type stored together. You cannot mix data types in a single array—an integer array contains only integers, a string array contains only strings.
Array Syntax in Java
Arrays are declared with square brackets after the data type (e.g., int[] roleNumbers). The reference variable points to an array object. You can initialize with a size (new int[5]) or directly with values (new int[]{23, 12, 45, 32, 15}).
Memory Management and Internal Workings
Stack vs Heap: Declaration and Initialization
Declaration (int arr;) happens at compile time and creates a reference variable in stack memory. Initialization (arr = new int[5];) happens at runtime and creates the actual array object in heap memory. This is called dynamic memory allocation.
1
Declaration: Reference variable created in stack memory
2
new Keyword: Object created in heap memory at runtime
3
Assignment: Reference variable points to heap object
4
Dynamic Memory Allocation: Memory allocated during execution
How arrays are allocated in Java memory
Continuous vs Non-Continuous Memory in Java
In C++, arrays occupy continuous memory blocks. In Java, heap objects are not guaranteed to be continuous (per Java Language Specification). The JVM manages memory allocation, so array elements may be scattered across different heap locations.
Default Values in Arrays
When an integer array is created, all elements default to 0. When a string (object) array is created, all elements default to null—a special literal value representing no object reference. Null can only be assigned to reference types, not primitives.
Integer Array Default
0 all elements
String Array Default
0 null references
Default values for different array types
Object Arrays vs Primitive Arrays
Primitive arrays (int, boolean, float) store values directly in stack memory. Object arrays (String, custom classes) store reference variables in the array that point to objects scattered throughout heap memory. Each element of an object array is itself a reference variable.
Array Indexing and Access
Zero-Based Indexing
Array indices start at 0, not 1. For an array of size 5, valid indices are 0, 1, 2, 3, 4. The last valid index is always size minus 1. Accessing an invalid index (e.g., arr[5] on a size-5 array) throws an ArrayIndexOutOfBoundsException.
1
Index 0
First element
2
Index 1
Second element
3
Index 2
Third element
4
Index size-1
Last element
Array indexing starts at 0
Reading and Modifying Array Elements
Access elements using arr[index]. Reading: int value = arr[2] retrieves the element at index 2. Modifying: arr[3] = 99 changes the element at index 3. Arrays are mutable—changes to array elements persist because the reference points to the same heap object.
Input and Output with Arrays
Using for Loop for Input
To fill an array with user input, use a for loop from index 0 to array.length-1. Each iteration reads one value using Scanner and stores it at arr[i]. The array.length property gives the array size without hardcoding.
1
Create Scanner object for input
2
Loop from i=0 to i<array.length
3
Read next integer with scanner.nextInt()
4
Store at arr[i]
5
Increment i and repeat
Taking array input with a for loop
Three Ways to Print Arrays
1) Manual for loop printing each element. 2) Enhanced for-each loop: for(int num : arr) print(num). 3) Arrays.toString(arr) converts array to formatted string with brackets and commas, internally using StringBuilder.
Two-Dimensional Arrays (2D Arrays)
2D Array Syntax and Structure
2D arrays use two square brackets: int[][] arr = new int[3][3]. The first number specifies rows (mandatory), the second specifies columns (optional). Internally, a 2D array is an array of arrays—each row is itself an array object stored separately in heap memory.
Jagged Arrays: Variable Column Sizes
Column size is not mandatory because each row is an independent array object. Rows can have different lengths: int[][] arr = new int[3][] allows the first row to have 3 elements, second row 2 elements, third row 4 elements. This is called a jagged array.
Accessing 2D Array Elements
Use two indices: arr[row][column]. arr[0] returns the entire first row (an array). arr[0][2] returns the element at row 0, column 2. arr.length gives number of rows. arr[i].length gives number of columns in row i.
Input for 2D Arrays with Nested Loops
Use nested for loops: outer loop iterates rows, inner loop iterates columns. For each row[i], the inner loop runs arr[i].length times to handle variable column sizes. Read input with arr[row][col] = scanner.nextInt().
1
Outer loop: for each row from 0 to arr.length
2
Inner loop: for each column from 0 to arr[row].length
3
Read input at arr[row][col]
4
Inner loop completes for one row
5
Outer loop moves to next row
Nested loop structure for 2D array input
Output for 2D Arrays
Use nested loops to print each element, adding a newline after each row. Alternatively, use enhanced for loop: for(int[] row : arr) print(Arrays.toString(row)) to print each row as a formatted string.
Arrays in Functions and Mutability
Passing Arrays to Functions
Java uses call-by-value, but when passing an array, a copy of the reference is passed. Both the original and copied reference point to the same heap object. Changes made inside the function affect the original array—arrays are mutable.
Mutable vs Immutable Behavior
Arrays are mutable: modifying arr[0] inside a function changes the original. Strings are immutable: reassigning a string inside a function does not affect the original. This distinction matters when designing functions that modify data structures.
ArrayList: Dynamic Arrays
Why ArrayList: Fixed Size Problem
Arrays require a fixed size at creation. If you don't know how many elements you'll need, ArrayList is the solution. ArrayList automatically grows as you add elements, eliminating the need to pre-declare size.
ArrayList Syntax and Declaration
ArrayList is part of Java's Collection Framework (java.util package). Syntax: List<Integer> list = new ArrayList<Integer>() or ArrayList<Integer> list = new ArrayList<>(). The generic type (e.g., Integer) specifies what data type can be stored. Primitives cannot be used directly; use wrapper classes (Integer, String, etc.).
ArrayList Methods: Add, Get, Set, Remove
list.add(value) appends an element. list.get(index) retrieves element at index. list.set(index, value) updates element at index. list.remove(index) removes element at index. list.contains(value) checks if value exists. list.size() returns number of elements.
ArrayList Internal Growth Mechanism
ArrayList maintains an internal fixed-size array. When capacity is reached, a new larger array is created (using a growth formula), old elements are copied, and the old array is discarded. This happens automatically, making ArrayList appear unlimited in size.
1
Initial capacity set (default or specified)
2
Elements added up to capacity
3
Capacity threshold reached
4
New larger array created
5
Old elements copied to new array
6
Old array discarded
ArrayList automatic resizing process
Iterating ArrayList with for Loop and Enhanced for
Use traditional for: for(int i=0; i<list.size(); i++) list.get(i). Or enhanced for: for(Integer num : list) print(num). Both work; enhanced for is cleaner when you don't need the index.
Multi-Dimensional ArrayList
ArrayList<ArrayList<Integer>> creates a 2D ArrayList. Each element is itself an ArrayList. Must initialize inner lists explicitly: list.add(new ArrayList<>()). Then access with list.get(i).add(value) or list.get(i).get(j).
Practical Array Problems
Swap Function
Swap two elements at indices i and j using a temporary variable: temp = arr[i]; arr[i] = arr[j]; arr[j] = temp. Useful for sorting and reversing operations. Changes persist because arrays are mutable.
Find Maximum Element
Assume first element is max. Iterate through array comparing each element with current max. If element is greater, update max. Return max after loop. Time complexity: O(n). Can be extended to find max in a range by specifying start and end indices.
Reverse Array Using Two-Pointer Technique
Use two pointers: start at index 0, end at index length-1. Swap elements at start and end. Move start forward, end backward. Stop when start >= end. This efficiently reverses the array in O(n) time with O(1) space.
1
Initialize start=0, end=length-1
2
While start < end:
3
Swap arr[start] and arr[end]
4
Increment start, decrement end
5
Array is reversed
Two-pointer reversal algorithm
Key Concepts Summary
New Keyword
The 'new' keyword creates an object in heap memory at runtime. For arrays: new int[5] allocates space for 5 integers in heap. Without 'new', only the reference variable is created (compile time); the actual object doesn't exist.
Null: Special Literal for Reference Types
Null is a special literal (not a type or object) representing 'no object reference'. By default, all reference variables point to null. Can be assigned to any reference type (String, arrays, objects) but not to primitives. Similar to 'None' in Python.
Edge Cases to Handle
When writing array functions, check for null arrays, empty arrays (length 0), and invalid indices. Return sentinel values (e.g., -1) or throw exceptions for invalid inputs. Proper edge case handling prevents runtime errors.
Worth quoting
"Array is basically a collection of your data types, it can either be primitives or objects."
— Kunal Kushwaha, at [2:39]
"Arrays are mutable in Java. Strings are immutable in Java."
— Kunal Kushwaha, at [42:30]
"In Java, there is no concept of pointers. You cannot get the address or anything."
— Kunal Kushwaha, at [13:09]
Try this
Create a program to take 5 integers as input into an array and print them using all three methods: manual for loop, enhanced for loop, and Arrays.toString().
Write a function to find the maximum element in an array and test it with different inputs including edge cases (empty array, single element, negative numbers).
Implement the swap function and use it to reverse an array using the two-pointer technique.
Create a 2D array program that takes 3x3 matrix input and prints it in matrix format with proper row and column alignment.
Write a program using ArrayList to store user-input integers until the user enters -1, then print all elements and calculate the average.
Implement a multi-dimensional ArrayList (ArrayList of ArrayList) to store and print a 3x3 matrix of integers.
Create a function that finds the maximum element in a specified range of an array (between start and end indices).
Write a program to demonstrate the difference between passing arrays to functions (mutable behavior) vs passing primitives (immutable behavior).
Made with Glimpse by Wozart
glimpse.wozart.com/v/35p26dsl
Share this infographic

More like this