Concepts / Object References and Variables

Object References and Variables

Instance variables of an object are reached with dot notation, written object_name.variable_name, following the rule that when B is part of A, its full name is A.B

  • Programming

The Two-Students Puzzle

Imagine two students who have the same name and the same scores on three tests. It feels natural to write one comparison and get a yes or no answer about whether they are the same student. Many beginners expect Java to work this way. It does not behave that way for objects, and the gap between expectation and behavior causes a common and persistent error. In this article you will see what Java actually compares when you use == on two objects, and you will learn a dependable way to check whether two objects hold the same data.

What do you think happens?

Two variables, std1 and std2, each refer to a different Student object. Both objects hold the name Ana and the scores 90, 85, and 77. What does std1 == std2 evaluate to?

  • true, because the contents match

  • false, because the two references lead to separate objects

Reveal answer
Answer:

false, because the two references lead to separate objects

The == operator applied to two object references asks whether the references lead to one and the same object. It does not look inside the objects to compare their instance variables. Since std1 and std2 lead to two separate objects, the result is false even though every field holds the same value.

Reaching Instance Variables with Dot Notation

Before you can compare the contents of two objects, you need a way to reach the contents of one object. Suppose a variable named std refers to an object that is an instance of a class called Student. That object carries its own instance variables: name, test1, test2, and test3. You reach each of them by writing the object's name, a dot, and the variable's name. The variable is therefore written as std.name, std.test1, std.test2, and std.test3.

This pattern follows a naming habit you will see throughout Java. When one thing B belongs to another thing A, you write the full name of B as A.B. The dot tells you that the item on the right lives inside the item on the left. Reading std.test2 therefore means: the test2 belonging to the object that std refers to.

stdreference to a Studentobjectstd.namestd.test1std.test2std.test3containscontainscontainscontains
Which object contains which, and how does the full name std.test2 show that test2 lives inside std?

Notice that the dot notation always starts from a reference. The expression std.test1 does not mean a free-standing variable called test1. It means the test1 stored inside whichever object std currently refers to. This matters because two different variables can refer to two different objects, and each object has its own separate copy of the same instance variable names.

java
Output
Ana
85
Notes on the code
  • std is a reference that leads to one Student object
  • std.name reads the name stored inside that object
  • std.test2 reads the test2 stored inside that same object
Best practice

Read an instance variable as object.variable, and always say aloud which object the reference points to. If you find yourself reading test2 with no object name in front of it, the code is referring to a different variable, not to the object's own field.

What == Actually Compares

The thing stored in std1 is a reference, a way of finding an object. The thing stored in std2 is another reference. The comparison std1 == std2 asks whether those two references lead to one and the same object. If they do, the result is true. If they lead to two separate objects, the result is false, even when every instance variable in those two objects holds identical values. The == and != operators test reference identity, not the data inside the objects.

std1Student object onename Ana, test1 90, test285, test3 77std2Student object twoname Ana, test1 90, test285, test3 77refers torefers to
When std1 == std2 is evaluated, are std1 and std2 attached to one shared object, or to two different objects whose fields happen to hold equal values?

The diagram shows the situation from the opening puzzle. The two objects have identical field values, but they are two objects. The references lead to different places, so std1 == std2 is false. The values match, but the question == answers is about whether the references lead to one object, and here they do not.

java
Output
false
true
true
Notes on the code
  • std1 and std2 lead to two separate objects with matching data
  • std1 != std2 is the negation of the identity test, so it is true here
  • std3 = std1 copies the reference, so std3 and std1 lead to the same object

Checking Each Instance Variable Separately

When the question you want answered is whether two objects hold the same data, you have to do the looking yourself. Compare each instance variable individually: the first, then the second, then the third. Then combine the results with && so that every comparison must hold before the overall answer is true. If any one field differs, the whole check fails.

java
Output
true
Notes on the code
  • std1.name.equals(std2.name) compares the content of the two name references
  • == on the int fields compares their stored numbers directly
  • && requires every comparison to be true

Notice the first check. The name is a reference-type instance variable, so it is compared with equals rather than ==. If you used == on name, you would be asking whether the two name references point to one object, which is the same identity question you already learned to recognize as the wrong one here. Using equals asks whether the names have the same content. The test scores are compared with == because they are values stored directly in each object.

Worked example

Comparing two students who differ in one score

std1 and std2 both have the name Ana and test1 equal to 90, but std2.test3 is 80 while std1.test3 is 77. Does the data check report that they hold the same data?

  1. 1
    Check the name

    std1.name.equals(std2.name) is true, because both names contain Ana.

  2. 2
    Check test1

    std1.test1 == std2.test1 is true, because both are 90.

  3. 3
    Check test2

    std1.test2 == std2.test2 is true, because both are 85.

  4. 4
    Check test3

    std1.test3 == std2.test3 is false, because 77 is not 80.

  5. 5
    Combine with &&

    Since one part of the && chain is false, the whole expression is false.

Result

The data check returns false. The objects do not hold the same data, even though the name and two of the three scores match.

Question askedHow it is writtenWhat it checksResult for two matching students
Are these the same object?std1 == std2Whether both references lead to one objectfalse
Are these different objects?std1 != std2Whether the references lead to different objectstrue
Do these hold the same data?field-by-field comparison joined with &&Whether every instance variable matchestrue

Identity checks and data checks answer different questions

Mistakes When Comparing Objects

  • Common mistake

    Expecting std1 == std2 to confirm that two students match

    What it looks like
    std1 == std2 printed false even though both students have name Ana and the same scores.
    Why it fails

    The operator compares the references, which lead to two separate objects, not the instance variables inside them.

    Do this instead

    Compare each instance variable individually, joined with &&, when you want to test whether the data matches.

  • Common mistake

    Using == on a reference-type instance variable such as name

    What it looks like
    std1.name == std2.name
    Why it fails

    This asks whether the two name references point to one object, not whether the names have the same content.

    Do this instead

    Use std1.name.equals(std2.name) to compare the content of the names.

  • Common mistake

    Forgetting the object name when reading an instance variable

    What it looks like

    Reading test2 alone when you meant std.test2

    Why it fails

    The dot notation starts from a reference. Without the reference, the expression does not identify the object's own field.

    Do this instead

    Write the full name object.variable, such as std.test2.

  • Common mistake

    Combining field checks with || instead of &&

    Why it fails

    With || a single matching field would make the whole check true, even when other fields differ.

    Do this instead

    Join the individual comparisons with && so that every one must hold.

Practice Comparing Two Objects

MEDIUM

Two Student references, a and b, each refer to a different object. Write a single boolean expression that is true only when the names match and test1, test2, and test3 all match. Then predict what your expression returns when a.name is Ana and b.name is Ana but b.test3 holds a different value from a.test3.

Hints
  • Compare name with equals, not with ==.
  • Use one comparison per instance variable and join them with &&.
  • A single false inside a && chain makes the whole expression false.

Key Takeaways

  • Instance variables are reached with dot notation as object_name.variable_name, following the rule that when B is part of A, its full name is A.B.
  • The == and != operators applied to two object references test whether the references point to the same object, not whether the objects' instance variables match.
  • To test whether two objects hold the same data, compare each instance variable individually and join the comparisons with && so that every one must hold.
  • Reference-type instance variables such as name should be compared with equals when you want to check their content.