equals()
and hashCode()
methods.
HashMap
collection.In this exercise, we're going to update the Jukebox application one more time. Instead of ignoring duplicate songs, now we want to count them. This means we both need to be careful about Song
equality—taking into account both artist and title—and we have to think carefully about which object(s) should do the counting, and how.
As we discussed at the end of class last week, song titles aren't enough to distinguish between different songs—and if we want to count how many times a song is played, we certainly don't want to give credit to the wrong artists! So, first, fix the Song
class so that two Song
objects are only treated as equal if they have the same title and the same artist. (If you change the equals()
method of a class, what else needs to change?)
Now, how exactly should we keep track of how many times each song is played? It's tempting to add a "countPlays" instance variable to the Song
class, and maybe an "incrementCount()" method. But think about object-oriented design... should a song "know" how many times it's been played? That means it would also have to know (or be told) to reset that count periodically. Plus, what if a song were available on multiple jukeboxes? Why should we expect a song to be able to keep track of all the places it's played? Additionally, if you think about how the jukebox application works, each Song
object really represents a single "play" of the song; if I have multiple objects representing multiple plays of the same song, which one should do the counting? So this idea, of having song objects count how many times they're played, doesn't sound like great design—number-of-plays is not really an "essential quality" of a song.
Instead, I think it's more a property of the device that plays songs. So, let's make it the responsibility of the jukebox to count the songs it plays—resetting the count will be much easier than (say) going through all the songs and resetting their individual counts.
That requires some kind of way to both keep track a list of all the songs that have been played so far and associate each of those songs with the number of times it's been played. Here's a bad idea: keep an array (or ArrayList) of Song
objects, and then set up another array (or ArrayList) of int
to hold the count of each cong, so that the elements in each array "match" each other. It's going to get time-consuming to search that array for a song—or, if we keep that array sorted, then we're going to have super-duper careful not to mess up the order of the count array.
Here's a better idea. The key in that last paragraph is associate: we want to associate each Song
with its count. Often, the word "associate" is a hint that we want to use a Map
structure. And that's exactly what we need to do. We can create a Jukebox
instance variable, maybe named songCount
, that will map a Song
object to its count. Specifically, we need to modify the book's Jukebox3
class. We'll declare a HashMap
instance variable:
HashMap<Song, Integer> songCount = new HashMap<Song,Integer>();Now, write a method
countSongs()
that iterates through songList
and uses songCount
to map every song that’s been played to the count of how many times it’s been played. And add code to the main()
method that uses songCount
to display the number of times each song has been played.
Here is the book's original code: Jukebox3.java Song.java
Of course, you'll have to generate your own input text file in order to test your code. Remember that this version of the Song
class reads in 4 "tokens" per line, so be sure your input file format matches what the code expects.
If you have time, write code that allows us to compare songs by both title and artist (that is, so that songs with the same title can still be put in order by the artist name.)