Popcorn hack 1

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

Changing b doesn’t affect a because int is a primitive type, and primitives store their actual values on the stack. When you assign b = a, a copy of a’s value (10) is made—so later changing b doesn’t change a.

On the other hand, array1 and array2 are references to an object (the array) stored on the heap. When you assign array2 = array1, both variables point to the same memory location in the heap. Changing one changes the shared array, so both see the update.

Stack: holds variables a, b, and references (addresses) to array1 and array2. Heap: holds the actual array object {99, 2, 3}.

Popcorn Hack #2

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

After haveBirthday(john) is called, John’s age becomes 21. This is because the method modifies the contents of the same Person object in memory. The reference p inside the method points to the same object as john, so updating p.age directly changes John’s age.

After reassignPerson(john) is called, John’s name and age remain “John” and 21. In this case, the method creates a new Person object and reassigns the local variable p to it, but this does not change what john points to outside the method.

Difference:

Modifying an object’s contents (like p.age = 21) changes the actual object on the heap that both references share.

Reassigning a reference (like p = new Person(…)) only changes the local reference variable—it does not affect the original variable outside the method.

Homework Hack 1

// Homework Hack #1: Object Creation Practice

public class ObjectCreation {
    public static void main(String[] args) {
        // 1. Create two Car objects using 'new'
        // Example: Car car1 = new Car("Tesla", 2024);
        Car car1 = new Car("Tesla", 2024);
        Car car2 = new Car("Ford", 2020);
        // 2. Print each car's info
        // Example: System.out.println(car1);
        System.out.println(car1);
        System.out.println(car2);
    }
}

class Car {
    // 1. Declare variables: brand, year
    String brand;
    int year;
    // 2. Create a constructor to set those variables
    Car(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }

    // 3. Add a method or toString() to display car info
    public String toString() {
        return brand + " (" + year + ")";
    }
}
ObjectCreation.main(null);
Tesla (2024)
Ford (2020)

Popcorn Hack #2

// Homework Hack #2: Heap vs Stack Storage Demo

public class HeapVsStack {
    public static void main(String[] args) {
        // 1. Create a primitive variable (int pages)
        int pages = 100;

        // 2. Create another primitive variable that copies it
        int pagesCopy = pages;
        // 3. Create a Book object (Book b1 = new Book("Java Basics");)
        Book b1 = new Book("Java Basics");
        // 4. Create another Book reference (Book b2 = b1;)
        Book b2 = b1;
        // 5. Change the original primitive and the Book title
        pages = 200;
        b1.title = "Advanced Java";

        // 6. Print both sets of values to compare behavior
        System.out.println("pages = " + pages);
        System.out.println("pagesCopy = " + pagesCopy);
        System.out.println("b1 = " + b1);
        System.out.println("b2 = " + b2);
    }
}

class Book {
    // 1. Declare variable: String title
    String title;
    // 2. Create a constructor to set the title
    Book(String title) {
        this.title = title;
    }

    // 3. Create a toString() to show the title
    public String toString() {
        return title;
    }
}
HeapVsStack.main(null);
pages = 200
pagesCopy = 100
b1 = Advanced Java
b2 = Advanced Java