Zum Hauptinhalt springen

Week 1 Day 3 — Pass-by-value, Identity, and Equality

Goal

Today I want the argument-passing model that opens many backend interviews.

Main questions:

  1. Is Java pass-by-value or pass-by-reference?
  2. Why can a method still mutate the caller’s object?
  3. What is identity vs equality?
  4. When do I use == and when do I use equals?

1. Java is pass-by-value

Every argument is copied into the parameter.

For a primitive, the value is copied.


void bump(int n) {
n = n + 1;
}

int x = 3;
bump(x);
// x is still 3

For an object, the reference is copied. The copy still points at the same heap object.


void rename(User user) {
user.setName("Ada"); // mutates the shared object — caller sees it
user = new User("Bob"); // rebinds only the local copy — caller unchanged
}

People say “objects are passed by reference.” That is the C++ meaning. In Java the reference value is passed. The callee cannot make the caller’s variable point somewhere else.

Memory sentence:

Java copies the value. For objects that value is the reference.


2. Mutation vs reassignment

Keep these two operations apart:

OperationWhat changesCaller sees it?
user.setName("Ada")Fields of the heap objectYes, same object
user = new User("Bob")The local reference onlyNo
user = nullThe local reference onlyNo

final on a parameter only blocks reassignment of that parameter. It does not make the object immutable.


void tag(final User user) {
user.setName("Ada"); // allowed
// user = new User("Bob"); // compile error
}

3. Identity vs equality

Identity: same heap object. Operator: ==.

Equality: same meaning according to equals. Default Object.equals is identity. Many types override it (String, Integer, records, well-written value objects).


User a = new User("Ada");
User b = a;
User c = new User("Ada");

a == b; // true: same reference
a == c; // false: two objects
a.equals(c); // true only if User overrides equals on the name

For types I did not write, I look at their contract. String.equals compares characters. String == is identity, which sometimes looks equal because of the string pool.

Memory sentence:

== asks “same object?” equals asks “same meaning?”


4. The string pool (just enough)

String literals are interned. new String("Ada") is a new heap object.


String a = "Ada";
String b = "Ada";
String c = new String("Ada");

a == b; // true: same interned object
a == c; // false
a.equals(c); // true

I never rely on == for String in application code. I use equals, or Objects.equals when either side may be null.


Objects.equals(left, right); // null-safe

5. Spring connection

  • Constructor injection copies a reference into a final field. The service and the container share the same repository object.
  • If I mutate a mutable bean that many services hold, every holder sees the change.
  • DTOs passed into a service are shared until I copy them. If I keep a request DTO on a singleton, I leak request data.
  • equals on entities is a later JPA topic. For now: identity (==) is the JVM fact; equality is a contract I must define.

6. Common traps

Trap 1: “Objects are passed by reference.”
The reference is copied. Reassignment does not escape the method.

Trap 2: final means immutable.
final blocks reassignment of the variable. The object behind a final reference can still change.

Trap 3: Using == for String or Integer because it “worked on my machine.”
Pooling and caches make identity look like equality until it does not.

Trap 4: Forgetting null in equals.
user.equals(name) NPEs if user is null. Prefer Objects.equals(user, name) or "Ada".equals(user).


Practice Questions and Answers

Question 1

Is Java pass-by-value or pass-by-reference?

Answer:

Pass-by-value. Primitives are copied. For objects, the reference is copied. The method can mutate the same heap object. It cannot reassign the caller’s variable.


Question 2

What does the caller see after this method?


void reset(User user) {
user = new User("nobody");
}

Answer:

Nothing changes for the caller. user is a local copy of the reference. The assignment points that copy at a new object. The caller’s variable still points at the original.


Question 3

What does final on a parameter guarantee?

Answer:

The parameter cannot be reassigned. The method can still mutate the object if the type is mutable.


Question 4

When is == the right comparison?

Answer:

When I care about identity: the same instance. Enums are a safe case because each constant is a single instance. For values (String, wrappers, records) I use equals.


Question 5

Why is this dangerous on a singleton bean?


@Service
public class OrderService {
private OrderRequest current;
public void place(OrderRequest request) {
this.current = request;
}
}

Answer:

The field stores a reference to request data on a heap object shared by every thread. Concurrent requests overwrite current. One user can see another user’s order. Request data belongs in method arguments, not in singleton fields.


Memory sentences

Java copies the value; for objects that value is the reference.

Mutation of the object is visible. Reassignment of the parameter is not.

== is identity. equals is meaning.

Next: Week 1 Day 4 — final and Immutability