Description
For this assignment you will create a class called Movie and observe its
behavior when it is managed by different kinds of “Film Archive” collections.
Information that is underlined and italicized has a high probability of appearing
on your next exam.
Late work will not be accepted.
Getting started
Create a new workspace directory, or use an existing one. Create a Java project
called hw3proj in the workspace. Create a package called movies in the project.
All classes and interfaces that you create should go in the movies package.
Class movie
Create a public class Movie with private instance variables String title
and int year. The class should declare that it implements the
Comparable interface, and should provide the following:
• A constructor that takes 2 arguments: a String and an int (in that order)
for initializing title and year.
• A method that satisfies the Comparable interface. Movies
should be compared first by title and then by year.
The Maltese Falcon The Thomas Crown Affair The Thomas Crown Affair
1941 1968 1999
• Methods getTitle() and getYear() that do the right thing.
• An equals() method that is compatible with the method that satisfies the
Comparable interface.
• A toString() method that returns “Movie” followed by 1 space followed
by the title followed by 1 space followed by open-parenthesis followed
by the year followed by close-parenthesis. Example:
Movie The Maltese Falcon (1941)
• A public static method getTestMovies(), which returns an array of 10
unique Movie instances. They don’t have to be real movies – it’s ok to
make them up. The 0th and 1st array elements must be 2 movies with the
same title but from different years (e.g. The Thomas Crown Affair 1968
and The Thomas Crown Affair 1999, or True Grit 1969 and True Grit
2010). The 2nd and 3rd elements (counting from 0) must be 2 movies with
different titles but from the same year (e.g. The Martian 2015 and Bridge
of Spies 2015). The 4th and 5th elements must be 2 different objects that
represent the same movie (same title and same year). The remaining
elements can be any movies you like.
• A hashCode() method. Use the following:
public int hashCode()
{
return title.hashCode() + year;
}
Interface FilmArchive
Create an interface called FilmArchive that defines 2 methods:
• getSorted(), which takes no args and returns ArrayList.
Implementations should return an array list whose members are unique
according to deep equality, and sorted according to the criteria in
Movie’s compareTo() method.
• add(), which takes one arg of type Movie and returns a boolean. If add()
is called where the arg already appears in the film archive, the method
should return false and otherwise do nothing; if the arg of add() does not
yet appear in the archive, it should be added as described below and the
method should return true.
3 implementing classes
Create 3 classes, named ListFilmArchive, HashFilmArchive, and
TreeFilmArchive, that implement the FilmArchive interface.
Class ListFilmArchive
This class should extend ArrayList. In your add() method, check every
movie in the array list for deep equality to the arg of add(). If you find a movie
that “equals()” the arg, just return false; if you don’t find one, add the arg to the
array list and return true.
Hint: you are overriding the add() method inherited from the ArrayList
superclass. When you detect that the arg movie doesn’t appear in the array list,
you want to call the superclass’ version of add(). To do that, use something like
this line:
boolean reallyAdded = super.add(aMovie);
“super.” in this overridden method tells Java “please use the version of add in
my superclass”.
For the getSorted() method, use a TreeSet to do the sorting. First
construct a TreeSet, passing the ArrayList into the TreeSet
constructor; since ListFilmArchive “isa” ArrayList, “this” is a reference
to the ArrayList that you want to pass. Then construct and return a new
ArrayList, passing the TreeSet into the ArrayList constructor; when
that ArrayList is constructed, the movies in the TreeSet will be added to it one
by one, in the TreeSet’s natural order, which is the order that you want. In
other words, this long paragraph describes 2 simple lines of code.
Class HashFilmArchive
This class should extend HashSet. It’s ok to add movies to a HashSet
because Movie has mutually compatible equals(), and hashCode() methods.
For the add() method, first read the documentation for add() in the
java.util.HashSet API page
(https://docs.oracle.com/javase/8/docs/api/java/util/HashSet.html ).
Convince yourself that this method does exactly what add() in
HashFilmArchive should do. Since the inherited method is acceptable, you
don’t need to create add() in HashFilmArchive. (But you do need to understand
why you don’t need to).
For the getSorted() method, do something similar to what you did in
ListFilmArchive.
Class TreeFilmArchive
This class should extend TreeSet.
For the add() method, first read the documentation for add() in the API page
for java.util.TreeSet
(https://docs.oracle.com/javase/8/docs/api/java/util/TreeSet.html ).
Convince yourself that this method does exactly what add() in
TreeFilmArchive should do. Since the inherited method is acceptable, you don’t
need to create add() in TreeFilmArchive.
For the getSorted() method, do something somewhat similar to, but simpler
than, what you did in ListFilmArchive and HashFilmArchive. All you need to do
is construct an ArrayList, passing “this” into the ArrayList ctor. Well,
that’s not all you need to do … you also need to understand why it works.
Testing your 3 FilmArchive classes
To test your classes, you will do what professional programmers do in the real
world: Create test inputs, think about what outputs those inputs will cause, run
the code, look at the output, and see if your expectations were met. If they were
met, that’s great. If not, either your expectations or your implementation was
wrong. Figure out where you are wrong, and correct your expectations or your
code.
You already have test inputs: the array returned by Movie.getTestMovies(). Be
sure that this array meets the requirements described above.
To test the ListFilmArchive class, add the following main() method:
public static void main(String[] args)
{
ListFilmArchive archive = new ListFilmArchive();
for (Movie m: Movie.getTestMovies())
archive.add(m);
for (Movie m: archive)
System.out.println(m);
System.out.println(“**************”);
for (Movie m: archive.getSorted())
System.out.println(m);
}
If you get a compiler error on the line that prints out a row of stars, delete the
quote signs and then type them back in. Some systems do weird things with
smart quotes. Stupid smart quotes!
Run ListFilmArchive as an app. Look at the number of movies that were
printed out, and their order. Are these what you expected?
To test HashFilmArchive, add the same main() to HashFilmArchive but change
“ListFilmArchive” to “HashFilmArchive”. Then add the HashFilmArchive main()
to TreeFilmArchive but change “HashFilmArchive” to “TreeFilmArchive”. This
is a common way to test individual classes in Java: you give each class a main()
method that tests just that class.
Let’s do science
So far in this class you have done programming. It’s time to do science.
Computer science, like all science, includes making observations and looking
for patterns. An entire branch of computer science involves determining how
slow or fast an algorithm will be. A novel algorithm, even if it’s brilliant, isn’t
worth very much if it won’t complete execution on practical data during your
lifetime. It isn’t enough for software to be correct; it also has to be efficient.
Expect a question on that last sentence on your next midterm.
In lecture you learned that inserting into a HashSet is extremely fast, while
similar functionality based on an ArrayList is increasingly slow as the list
expands. It’s time to experience this for yourself.
Create the following class:
package movies;
public class HashAnalyzer
{
public static void main(String[] args)
{
HashFilmArchive archive = new HashFilmArchive();
for (int i=0; i<100000; i++)
{
archive.add(new Movie(“Movie” + i, 2017));
if (i%1000 == 0)
System.out.println(i);
}
System.out.println(“DONE”);
}
}
The main() method creates 100,000 fake movies and puts them into a
HashFilmArchive. Every 1000 insertions, it prints out a message. When you
run the app, the time interval between messages will give you feedback about
time performance of the add() method of HashFilmArchive. Now run the app.
Do you notice anything about the interval between messages? Is it long or
short? Does it increase as the archive grows?
Create a second analyzer class called ListAnalyzer. It should be just like
HashAnalyzer, except it should use a ListFilmArchive. Run the app. Now what
do you notice about the interval between messages.
Comments
Every class and interface should start with a descriptive comment. Every
method whose body is longer than 1 line should have a comment before the
method declaration. In this assignment the constructors are trivial, so they
don’t need comments. Non-trivial methods (like compareTo or getTestMovies
in the Movie class) might need internal comments.
A Man forComments should be accurate and helpful.
Submission
As usual, export your project as a JAR file (not an Executable JAR file) and
upload to Canvas. Be sure your jar contains all your sources.