public class MemoryDemo {
    public static void main(String[] args) {
        // Stack variables
        int a = 10;
        int b = a;  // Copy of value
        b = 20;     // Changing b doesn't affect a
        
        System.out.println("Primitives (Stack):");
        System.out.println("a = " + a);  // Still 10
        System.out.println("b = " + b);  // Now it's 20
        
        // Heap variables
        int[] array1 = {1, 2, 3};
        int[] array2 = array1;  // Copy of reference (address)
        array2[0] = 99;         // Changing array2 DOES affect array1
        
        System.out.println("\nArrays (Heap):");
        System.out.println("array1[0] = " + array1[0]);  // Now it's 99!
        System.out.println("array2[0] = " + array2[0]);  // Also 99
    }
}

MemoryDemo.main(null);
Primitives (Stack):
a = 10
b = 20

Arrays (Heap):
array1[0] = 99
array2[0] = 99

Tasks

Why does changing b not affect a, but changing array2 affects array1?

a and b are primitive types, so b gets a copy of a’s value. Changing b doesn’t change a.
array1 and array2 are references to the same array object in the heap, so modifying one changes both.

Stack vs. Heap

The stack holds variable names and references (a, b, array1, array2) while the heap stores the actual array object {1, 2, 3}, which both array1 and array2 point to.

Examine

Predicted Output

Before birthday: John is 20
Inside method: John is now 21
After birthday: John is 21

Before reassign: John is 21
Inside reassign: New Person is 99
After reassign: John is 21

Actual Output

public class PersonDemo {
    static class Person {
        String name;
        int age;
        
        Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
    
    public static void haveBirthday(Person p) {
        p.age = p.age + 1;  // Modifying object content
        System.out.println("Inside method: " + p.name + " is now " + p.age);
    }
    
    public static void reassignPerson(Person p) {
        p = new Person("New Person", 99);  // Reassigning reference
        System.out.println("Inside reassign: " + p.name + " is " + p.age);
    }
    
    public static void main(String[] args) {
        Person john = new Person("John", 20);
        
        System.out.println("Before birthday: " + john.name + " is " + john.age);
        haveBirthday(john);
        System.out.println("After birthday: " + john.name + " is " + john.age);
        
        System.out.println("\nBefore reassign: " + john.name + " is " + john.age);
        reassignPerson(john);
        System.out.println("After reassign: " + john.name + " is " + john.age);
    }
}
PersonDemo.main(null);
Before birthday: John is 20
Inside method: John is now 21
After birthday: John is 21

Before reassign: John is 21
Inside reassign: New Person is 99
After reassign: John is 21

Questions

  1. John’s age is 21 because the method changes the same object’s age field in the heap.

  2. John’s name is “John” and age is “21” because reassignPerson only changes its local copy of the reference, not the original.

  3. Modifying an object’s contents changes the data inside the same heap object and reassigning a reference only changes which object a variable points to.

Homework

Hack 1



public class ObjectCreation {
    public static void main(String[] args) {
        // Create two Car objects using 'new'
        Car car1 = new Car("Tesla", 2024);
        Car car2 = new Car("Toyota", 2020);

        // Print each car's info
        System.out.println(car1);
        System.out.println(car2);
    }
}

class Car {
    // Declare variables
    String brand;
    int year;

    // Constructor
    Car(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }

    // toString method to display info
    public String toString() {
        return brand + " (" + year + ")";
    }
}
ObjectCreation.main(null);
Tesla (2024)
Toyota (2020)

Hack 2

public class HeapVsStack {
    public static void main(String[] args) {
        // Creating a primitive variable 
        int pages = 300;

        // Create another primitive variable which will copies it
        int pagesCopy = pages;

        // Creating a Book object
        Book b1 = new Book("Java Basics");

        // Creating another Book reference
        Book b2 = b1;

        // Changing the original primitive and the Book title
        pages = 500;
        b1.title = "Advanced Java";

        // Printing both sets of values to compare behavior
        System.out.println("Primitives (Stack):");
        System.out.println("pages = " + pages);
        System.out.println("pagesCopy = " + pagesCopy);

        System.out.println("\nObjects (Heap):");
        System.out.println("b1 = " + b1);
        System.out.println("b2 = " + b2);
    }
}

class Book {
    // Declaring variable
    String title;

    // Constructor
    Book(String title) {
        this.title = title;
    }


    public String toString() {
        return "Book title: " + title;
    }
}
HeapVsStack.main(null);
Primitives (Stack):
pages = 500
pagesCopy = 300

Objects (Heap):
b1 = Book title: Advanced Java
b2 = Book title: Advanced Java