Skip to main content
Logo image

Section 9.2 Object equality

In SectionΒ 7.1Β Manipulating strings we learned that we needed to use the equals method to test whether two String values were the same if what we cared about was whether they contained the same text. Now that we understand object references we can dig a bit deeper into exactly why that is.

Subsection 9.2.1 Reference equality

Watch the following video which shows what happens in memory as both primitive types like int and reference types like Dog are compared with == in a physical model of Java memory.
As the video shows we can also use the == or != to test if two reference values, refer to the same object. In the video, she used Dog objects. In the figure below, we use Turtle objects, creating two Turtle objects assigned to variables juan and mia. Because each variable is assigned to the result of calling the Turtle constructor they do not refer to same object.
Then, we create a new variable called friend, assigning it the value from mia. The turtle object mia referenced is now also referenced by the variable friend because each variable holds a copy of the same reference. This is sometimes called an aliases because there are two names, mia and friend that refer to the same object in memory. If two reference variables refer to the same object like the turtle on the right in the image below, the test with == will return true which you can see in the code below.
Figure 9.2.1. Turtle Reference Equality

Activity 9.2.1.

What will the code below print out? Try to guess before you run it! Then, add another Turtle friend2 and set it to juan. Does friend2 == juan? Does friend2 == friend? Print out the Boolean expressions for these.

Subsection 9.2.2 String equality

While == and != have a clear meaning when comparing references, with object types we often care about a different notion of equality that looks at the values stored an objects’ instance variables to decide if they are the same. This is particularly true of classes like String that represent immutable values that just happen to be stored in a more complex way than primitive types like intand double.
The equals method for Strings compares two strings letter by letter. s1.equals(s2) is true if s1 and s2 have all the same characters in the same order. It is beyond the scope of the AP curriculum but any class can define its own equals method to compare instances of the class in some meaningful way. By default all classes have an equals method that just uses == but many classes will provide a more meaningful equals so in general whenever you are testing whether two non-primitive values are the same you should use equals unless for some reason you specifically care about whether they are literally the same (or different) objects in memory.
The figure below shows how a set of variables can include String values that are both == and equals and not. The value of a is neither == nor equals to any of the other variables’ values since it is the only String with the contents "hi". The other three variables’ values are all equals to each other since they all contain the text "bye" but only c and d are == since they reference the same actual object. The values of b and c are not == because whenever a String (or any other object) is created with new, it is always a new object that is not == to any other.
Figure 9.2.2. String aliases
The following video traces through the code above and shows how == and equals work with String objects in memory.
Here’s the representation of memory where s2 and s3 refer to the same String object.
Figure 9.2.3. s2 and s3 are aliases referring to the same String object

Activity 9.2.2.

If you run the following, what will be printed?

Activity 9.2.3.

What will the following print? Run the code to see the difference between == and equals with new Strings that are both β€œHello”. Then, write the if statements described below to test the equality of s1 and s3 to see if capitalization matters.
Watch the video below to see how this code works in memory. Since we used the new keyword, two different String objects will be created that each have the characters Hello in them. So s1 == s2 will be false since they don’t refer to the same object, but s1.equals(s2) is true since the two different objects contain the same characters in the same order.
Here is the representation of these String objects in memory.
Figure 9.2.4. Two strings that are equal with equals but not with ==.

Note 9.2.5.

Strings values that come from string literals like String s = "Hello" behave a little differently because Java makes sure, as a way of saving memory, that each unique string literal is represented by the same object in memory. Thus two string literals with the same content would in fact be ==. But that is pretty esoteric Java knowledge and nothing on the AP exam would expect you to know that and almost no Java code is written to take advantage of that fact.

Activity 9.2.4.

Which of the following is true after the code executes?
String s1 = new String("hi");
String s2 = new String("bye");
String s3 = new String("hi");
s2 = s1;
  • s1 == s2 && s1 == s3
  • Do s1 and s3 refer to the same object?
  • s1 == s2 && s1.equals(s3)
  • Yes s2 was set to refer to the same object as s1 and s1 and s3 have the same characters.
  • s1 != s2 && s1.equals(s3)
  • Did you miss that s2 was set to refer to the same object as s1?

Activity 9.2.5.

Which of the following is true after the code executes?
String s1 = new String("hi");
String s2 = new String("bye");
String s3 = new String("hi");
  • s1 == s2 && s1 == s3
  • Do s1 and s2 refer to the same object?
  • s2.equals(s3) && s1.equals(s3)
  • Does s2 have the same characters as s1 or s3?
  • s1 != s3 && s1.equals(s3)
  • s1 and s3 refer to different string objects but they contain the same characters "hi" in the same order.

Activity 9.2.6.

Which of the following is true after the code executes?
String s1 = new String("hi");
String s2 = new String("bye");
String s3 = new String("hi");
  • s1 == s3 && s1.equals(s3)
  • Since s3 uses the new operator it will not refer to the same object as s1.
  • s2.equals(s3) && s1.equals(s3)
  • Do s2 and s3 have the same characters in the same order?
  • !(s1 == s2) && !(s1 == s3)
  • All of the variables refer to different objects. But, s1.equals(s3) would be true since they have the same characters in the same order.

Subsection 9.2.3 Comparing with null

One time we do commonly use == or != with reference values is to compare a reference value to null to see if it safe to use. Remember that accessing an instance variable or invoking a method on null produces a NullPointerException so if we don’t know that a reference is non-null we need to check before we use it.
A common idiom is to use the short-circuit evaluation of && which ensures that if the first expression in the && is false, it doesn’t evaluate the second expression since it already knows the whole && test is false. So we can write something like:
if (s != null && s.indexOf("x") != -1) { ...
to safely test whether s contains the substring "x" even if s may be null.

Activity 9.2.7.

Try the following code to see a NullPointerException (if you don’t see the exception because of the autograding, you can copy it into the pencil icon scratch area to run it without the grader). Since s is null, trying to access indexOf on s throws an NullPointerException. Comment out the first if statement and run the program again. The second if statement avoids the error with shortcircuit evaluation. Because s != null is false, the rest of the Boolean expression is not evaluated. Now, change s to set it to "apple" instead of null in the first line and run the code again to see that the if statements can print out that β€œapple contains an a”.
The following video shows how the null string reference works in memory.
You have attempted of activities on this page.