First Part

Learning Objectives

  • Create your own method equals(Object o)
  • Implement a parametrized interface
  • Use the interface java.util.Comparator<T>

Section 1: the method equals

As you know, the class Object defines a method equals.

                  
public class Object {

    // ...

    public boolean equals(Object obj) {
        return this == other;
    }

}
                

Since in Java, every class inherits from the class Object, every class inherits the method boolean equals(Object obj). This is true for the predefined classes, such as String and Integer, but also for any class that you will define.

The method equals is used to compare references variables. Consider two references, a and b, and the designated objects.

  • If you need to compare the identity of two objects (do a and b designate the same object?), use "==" (i.e. a == b );
  • If you need to compare the content of two objects (is the content of the two objects the same?), use the method "equals" (i.e. a.equals(b)).

In this first part, we are going to create a simple class Book. This class is quite minimal. It contains the following:

  • An instance variable author of type String;
  • An instance variable title of type String;
  • An instance variable year of type int (the publication year of that book);
  • A contructor Book(String author, String title, int year), which receives that new instance's author, title and publication year as paramters;
  • A method toString(), which returns a String representation of that instance, using the format "author: title (year)";
  • A method equals(Object o).

We want our implementation to be as robust as possible. In particular, the method equals should handle every particular case you can think about. Make sure your code passes all the provided JUnit tests.

Question 1.1:

Provide an implementation of the class Book. Use the provided template as a starting point.

Section 2: the interface java.util.Comparator<T>

In the previous laboratory, we have used the interface Comparable to create objects of type Post. A comparable object (implementing the Comparable interface) overrides the method compareTo and is capable of comparing itself with another object.

Unlike Comparable, a class implementing the interface Comparator is external to the element type we are comparing. Such a class must implement the methods compare and equals, to define and impose the sort order.

Sort methods such as Collections.sort or Arrays.sort take a instance of Comparator as a parameter.

For this exercise, we will implement an application for managing a library. The Library class will have a list of Book instances. We will be using the resizable-array implementation offered by the class ArrayList, which automatically increases the capacity as new elements are added to the list.

The idea is that the method sort of the class ArrayList will use the method compare of the comparator when sorting the elements of the list. Therefore, the method compare needs to handle elements that are of a type which is compatible with the type of the elements in the ArrayList.

Since Comparator is an interface, it needs a concrete implementation. Depending on the criterion for ordering, we can have multiple implementations through different classes and obtain different results when sorting.

Note that the class ArrayList is parameterized. In our case, we use ArrayList<Book>. Our ArrayList instance will hold instances of the class Book. Therefore, its method sort needs to compare instances of the Book class, and requires an instance of Comparator<Book> for this.

Thus, the class Library will have a list of Book instances stored in an instance of ArrayList. Using a Comparator, we want to be able to sort our library by authors first, then by title, then by year of publication (of course, in a real case we would want to have several Comparators and sort our library in different orders).

The class Library has the following methods:

  • void addBook (Book b): adds a Book instance to the library;
  • void sort(): sorts the books using a Comparator;
  • void printLibrary(): prints all the book in their current order of the list.

Question 1.2:

Provide an implementation of the class Library as well as of BookComparator. Use the provided template as a starting point for the class Library and the provided template for BookComparator.

Second Part

Learning Objectives

  • Create and implement an interface
  • Create an abstract class
  • Further understanding of inheritance

Abstract classes and interfaces

In mathematics, a series is an infinite sequence of terms added together. The partial sum of the series, \( S_n \), is the sum of the first \( n \) terms. $$ S_n = \sum_{i=1}^{n} a_i $$ Here, you must create a class hierarchy, as illustrated by the UML diagram below, such that all the series have a method next, which returns the next \( S_n \). The first call to the method next returns \( S_1 \), which is $$ a_1 $$ the next call to the method next returns \( S_2 \), which is $$ a_1 + a_2 $$ the next call to the method next returns \( S_3 \), which is $$ a_1 + a_2 + a_3 $$ and so on. The implementation of the method next is specific to the type of series, here Arithmetic and Geometric. Specifically, this hierarchy consists of the interface Series, an abstract class called AbstractSeries, as well as two concrete implementations, called Arithmetic and Geometric.

UML diagram of AbstractSeries, Series, Arithmetic, and Geometric. Series is an interface. It declares a public method called next that has no parameter and it returns a value of type double. AbstractSeries is an abstract class. It implements the interface series. It declares a public method called take that takes a parameter of type n and the return type is array of double. Arithmetic and Geometric are subclasses of AbstractSeries.

Here is a test program that illustrates the intended use of the classes:

  • for the partial sum of an Arithmetic Series with 1 as the first term and 1 as common difference;
  • for the partial sum of a Geometric Series with 1 as the first term and 0.5 as common ration.

                  
public class TestSeries {

    public static void main(String[] args) {

        AbstractSeries sn;
        double[] tuple;

        sn = new Arithmetic();

        System.out.println("The first five terms of the arithmetic series are:");

        for (int n=0; n<5; n++) {
            System.out.println(sn.next());
        }

        sn = new Geometric();

        System.out.println();
        System.out.println("The first five terms of the geometric series are:");

        tuple = sn.take(5);

        for (int n=0; n<5; n++) {
            System.out.println(tuple[n]);
        }

    }
}
                           

Here is the expected output:

> TestSeries.java
> java TestSeries
The first five terms of the arithmetic series are:
1.0
3.0
6.0
10.0
15.0

The first five terms of the geometric series are:
1.0
1.5
1.75
1.875
1.9375
>
                

The first loop displays the values 1.0, 3.0, 6.0, 10.0, 15.0, whilst the second one displays, 1.0, 1.5, 1.75, 1.875, 1.9375.

Question 2.1: Series

Create an interface called Series. It declares a method called next that has a return-type double.

Use the provided template as a starting point.

Question 2.2: AbstractSeries

Write the implementation of the abstract class AbstractSeries. It implements the interface Series. The class implements a method called take that returns an array containing the next k partial sums of this series, where k is the formal parameter of the method take.

Use the provided template as a starting point.

Question 2.3: Arithmetic

Implement the class Arithmetic, which is a subclass of AbstractSeries. In this class, the first call to the method next returns the value 1.0, the second call returns the value 3.0, the third call returns 6.0, the fourth call returns 10.0, etc. The general formula is as follows, the \( i \)th call to the method next returns \( S_{i-1} + i \), where \( i \in 1, 2, 3\ldots \) and \( S_{i-1} \) is the value that was returned by the previous call to the method next. $$ S_n = \sum_{i=1}^{n} i $$

The first 5 partial sums of the arithmetic series are: $$S_1 = 1$$ $$S_2 = 1 + 2 = 3$$ $$S_3 = 1 + 2 + 3 = 6$$ $$S_4 = 1 + 2 + 3 + 4 = 10$$ $$S_5 = 1 + 2 + 3 + 4 + 5 = 15$$

Use the provided template as a starting point.

2.3 Geometric

Implement the class Geometric, which is a subclass of AbstractSeries. Each call to the method next produces the next partial sum of the series according to the formula below. The first call returns 1.0, the second call returns 1.5, the third call returns 1.75, etc. You can use Math.pow(a, b), which returns \( a^b \), for your implementation. $$ S_n = \sum_{i=0}^{n} \frac{1}{2^i}$$

The first 5 partial sums of the geometric series are: $$ S_1 = 1 $$ $$ S_2 = 1 + \frac{1}{2} = 1.5 $$ $$ S_3 = 1 + \frac{1}{2} + \frac{1}{4} = 1.75 $$ $$ S_4 = 1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} = 1.875 $$ $$ S_5 = 1 + \frac{1}{2} + \frac{1}{4} + \frac{1}{8} + \frac{1}{16} = 1.9375 $$ A call to the method next produces the next partial sum, i.e. the next value of \( S_n \).

Use the provided template as a starting point.

Part 3

Create and submit a zip folder (1 point)

Instructions

  • Create a directory lab5_123456, where 123456 is replaced by your student number.
  • Inside this directory, place the 7 .java files for this lab. Include only your source code. Do not include any class files or any other files; only Java files.
  • In this directory, also create a file README.txt which is a text file containing your name, student number and a brief description of the content of the directory:
    
    Student name: Jane Doe
    Student number: 123456
    Course code: ITI1121
    Lab section: B-2
    
    This archive contains the 8 files of lab 5, that is, this file (README.txt),
    plus Book.java, Library.java, BookComparator.java, Series.java, AbstractSeries.java, Arithmetic.java, Geometric.java.
    
                        
  • Create a zip file lab5_123456.zip containing the directory lab5_123456 and all of the java files.
  • Verify that your archive is correct by uncompressing it somewhere and making sure that all the files and the directory structure are there.
  • Submit the archive using https://uottawa.brightspace.com/

Important remarks!

We are using automated scripts to test and grade your lab submission. Therefore, you must follow these instructions exactly. In particular:
  • Your naming of all the files and methods must be exact. Copy/paste the starter code provided during the lab to avoid problems.
  • You MUST submit a .zip; not individual files; not a .rar, not a .7z, or anything else.
  • All the required java files must be present and must compile (that is, running javac *.java must not produce any errors), even if you were unable to complete an exercise.
  • Even if you could not solve an exercise's solution completely, you have to hand in a file with the methods that compiles (you can put "return 0" if you gave up).
  • Your submission is due by Tuesday 11:59PM the week after the lab. You can submit as often as you want before then, but not after. Only your last submission before the deadline will be considered.

JUnits

To help you making sure that your code is correct, we have prepared some JUnit tests. Refer to the Readme.txt in the zip file for some additional information.

Resources

Table of Contents