When I started learning object-oriented programming in Java, I hit a wall that I think a lot of beginners hit: I thought I understood how variables worked, until objects entered the picture. Here's the mistake I made and what actually clarified it for me.
The mistake
In Java, primitive types (int, double, boolean, char, etc.) work exactly how you'd expect — when you assign one variable to another, you get a copy.
int a = 5;
int b = a;
b = 10;
System.out.println(a); // 5
System.out.println(b); // 10
Changing b doesn't touch a. Simple enough. But then I ran into this with objects:
class Dog {
String name;
}
Dog dog1 = new Dog();
dog1.name = "Rex";
Dog dog2 = dog1;
dog2.name = "Max";
System.out.println(dog1.name); // Max ??
I expected dog1.name to still be "Rex", the same way a stayed 5 earlier. But it printed "Max" instead. That's the moment it clicked that objects don't work the same way as primitives.
What's actually happening
With objects, the variable doesn't hold the object itself — it holds a reference (basically an address) pointing to where the object lives in memory. When I wrote Dog dog2 = dog1;, I didn't copy the dog. I copied the address. So dog1 and dog2 were both pointing at the exact same object in memory. Changing dog2.name changed the only Dog object that existed — the one both variables were pointing to.
It's the difference between copying a letter versus copying the address written on an envelope. If you copy the address and someone repaints the house at that address, both copies of the address now point to a freshly painted house — because there was only ever one house.
Why this matters in practice
This isn't just a theory question — it causes real bugs. A common one: passing an object into a method, modifying it inside the method, and being surprised that the original object changed too.
public static void rename(Dog d) {
d.name = "Buddy";
}
Dog myDog = new Dog();
myDog.name = "Rex";
rename(myDog);
System.out.println(myDog.name); // Buddy
Since myDog is a reference, passing it into rename() passes a copy of the reference, not a copy of the object. Both point to the same Dog, so modifying it inside the method affects the original.
The one exception that confused me more: Strings
Strings in Java are objects too, but they behave a bit differently because they're immutable — once created, a String's content can never change. So this works the way you'd intuitively expect:
String s1 = "hello";
String s2 = s1;
s2 = "world";
System.out.println(s1); // hello
System.out.println(s2); // world
This looks just like the primitive example, but for a different reason: s2 = "world" doesn't modify the existing String — it makes s2 point to a brand new String object entirely, leaving the original one (and s1) untouched.
My takeaway
The rule that finally stuck for me: primitives copy their value, but object variables copy their reference (the address), not the object itself. If two variables point to the same object, changing the object through one variable will show up through the other too — unless the object is immutable, like Strings, in which case "changing" it actually creates a new object instead.
Once I stopped thinking of object variables as "boxes holding values" and started thinking of them as "sticky notes with an address on them," the rest of OOP made a lot more sense.
Final-year software engineering student, writing about what I'm learning in my courses.
Top comments (0)