Comparing Object References

A variable whose type is a class stores a reference, which locates an object kept elsewhere in memory. A music app's Song class shows what that means for comparisons.
Method HeaderDescription
public Song(String title, int seconds)Creates a song with the given title and length in seconds.
public int getSeconds()Returns this song's length in seconds.
public boolean equals(Object other)Tests whether other is a Song whose title and length both match this song's.
Same object, or same contents
Song opener = new Song("Opening", 200);
Song encore = new Song("Opening", 200);
Each new creates an object, so there are two Song objects, with the same title and the same length. Applied to references, == asks whether two references are to one object. Here opener == encore is false, since the two variables refer to different objects.
Whether two songs carry the same information is a question for equals. For Song, the documentation says the title and the length must both match, so opener.equals(encore) is true. A song created as new Song("Opening", 180) would not be equal to opener, since the lengths differ.
Two references to one object
The app's Player class keeps a reference to the song it is playing.
Method HeaderDescription
public void play(Song s)Starts playing s.
public Song getPlaying()Returns the song being played, or null if nothing is playing.
public Song getQueued()Returns the song queued to play next, or null if nothing is queued.
Suppose player refers to a Player object. After player.play(opener);, the call player.getPlaying() returns the reference stored in the player, and player.getPlaying() == opener is true: both are references to one object. Comparing it with encore by == gives false, even though the two songs are equivalent.
A reference to no object
A reference that is null refers to no object, and some methods return null on purpose. Suppose now that player's queue is empty. Then player.getQueued() == null is true. A comparison with null never fails, but calling a method through a null reference throws a NullPointerException, since there's no object to run it on. So a program that uses the queued song tests for null first.
Song next = player.getQueued();
if (next == null)
{
System.out.println("Queue is empty");
}
else
{
System.out.println(next.getSeconds());
}
The call next.getSeconds() is in the else body, so it runs only when next refers to a song.