Worksheet: J4 | CS 2113 Software Engineering - Fall 2023

Worksheet: J4

Worksheets are self-guided activities that reinforce lectures. They are not graded for accuracy, only for completion. Worksheets are due by Sunday night before the next lecture.

Create a new repo using all the steps in Lab 0 called yourgitusername-worksheet-J4. Submit a file called worksheet-J4.md in your repo for this assignment.

Note

Attempt to answer these questions before running the code. This will improve your ability to analyize and reason about code without an IDE or compiler. This skill we be helpful on the exams.

Questions

  1. Consider the class declaration below:

    // Is this possible?
    public class Lion extends Mammal, Carnivore {
        // ...
    }
    
    • Explain why the following class declaration is not possible in Java.
    • What are the limitations of the extends key word?
    • How can you accomplish this inheritance structure task in Java?

    Reveal Solution

  2. What are some of the functional differences between an abstract class and an interface? Use the example below to answer this question.

    public abstract class Employee {
        // ...
    }
    
    // vs.
    
    public interface Employee {
        //...
    }
    

    Reveal Solution

  3. Consider the interfaces for a Stack and Queue of ints.

    public interface Stack {
       public void push(int v);
       public int pop();
       public int peek();
    }
    
    public interface Queue {
       public void enqueue(int v);
       public int dequeue();
       public int peek();
    }
    

    Now suppose you had a LinkedList implementation to store ints with the following methods defined.

    public class LinkedList implements Stack, Queue {
      public LinkedList() {/*...*/}
      public void addToFront(int v) {/*...*/}
      public int rmFromFront() {/*...*/}
      public void addToBack(int v) {/*...*/}
      public void rmFromBack() {/*...*/}
      
      //FINISH HERE
      
    }
    

    Using those methods in LinkedList complete the realization of a Stack and Queue:

    Reveal Solution

  4. Rewrite the Stack and Queue interfaces from above to be generic, as well as the LinkedList. Explain how this is now generic to manage collections of any class.

    Reveal Solution

  5. Suppose you have interfaces Adder and Multiplier:

    public interface Adder<T> {
        T add(T a, T b);
    }
    
    public interface Multiplier<T> {
        T multiply(T a, T b);
    }
    

    Finish the implementation of the IntegerCalculator and FloatCalculator classes below.

    public class IntegerCalculator implements Adder<Integer>, Multiplier<Integer> {
        private String calculatorName;
    
        public IntegerCalculator(String calculatorName) {
            this.calculatorName = calculatorName;
        }
    
        public String getCalculatorName() {
            return calculatorName;
        }
    
        // TODO: add the methods needed to implement the adder and multiplier interfaces.
    }
    
    public class FloatCalculator implements  Adder<Float>, Multiplier<Float> {
        private String calculatorName;
    
        public FloatCalculator(String calculatorName) {
            this.calculatorName = calculatorName;
        }
    
        public String getCalculatorName() {
            return calculatorName;
        }
    
        // TODO: add the methods needed to implement the adder and multiplier interfaces.
    }
    

    Reveal Solution

  6. Review the following Java util data structures:

    For each,

    • Provide a two-to-three sentence description of each class
    • For each interface realized by these classes, also provide a two-to-three sentence description.
    • Finally draw a UML diagram that connects all of these classes back to object

    Reveal Solution

  7. Take a look at the documentation for LinkedHashSet: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/LinkedHashSet.html
    and HashSet:
    https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/HashSet.html

    When would it be preferable to use a LinkedHashSet instead of a HashSet?

    Reveal Solution

  8. The code below does not use Java generics. Update it to do so. Notably, there should not need casting, but no, the solution isn’t just removing the (String) casting before the .get method.

    import java.util.HashMap;
    
    public class TestHashMap {
    
        public static void main (String[] argv) {
            // Create a new hashmap.
            HashMap fabFour = new HashMap();
    
            // Insert four key and value pairs.
            fabFour.put("John", "John Lennon");
            fabFour.put("Paul", "Paul McCartney");
            fabFour.put("George", "George Harrison");
            fabFour.put("Ringo", "Ringo Star");
    
            // Use a key to retrieve a value.
            String fullName = (String) fabFour.get("Ringo");
    
            // Prints "Ringo Star"
            System.out.println(fullName);
        }
    }
    

    Reveal Solution

  9. Provide a 1-to-2 paragraph explanation for why we need Generics. You can use the sample code (above and below) to over this explanation.

    Reveal Solution

  10. What is “Erasure” with java generics?

    For the code below, what does the code “erase” to?

     public static void main(final String args[]) {
            Shelf<String> favorite_words = shelfBuilder();
            favorite_words.addItem("Zoetrope");
            favorite_words.addItem("Succinct");
            //...        
            String s = favorite_words.getItem(1);
            System.out.println(s);
        }
    

    Reveal Solution

  11. Finish the main method in the TestShelf class above.

    Expected output:

    Shakespeare Characters: Hamlet Othello Cordelia Juliet
    Famous Integers: 13 23 42 1729
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Shelf<T> {
        private List<T> shelfItems;
    
        private String shelfName;
    
        public Shelf(String shelfName) {
            this.shelfName = shelfName;
            shelfItems = new ArrayList<T>();
        }
    
        public int addItem(T item) {
            shelfItems.add(item);
            return shelfItems.size();
        }
    
        public void printShelf() {
            System.out.print(shelfName + ": ");
            for(T item: shelfItems) {
                System.out.print(item.toString() + " ");
            }
            System.out.println();
        }
    }
    
    public class TestShelf {
        public static void main(final String args[]) {
    
            // TODO: Create a shelf to store Shakespeare character names:
            //       Hamlet, Othello, Cordelia, and Juliet
            // TODO: Then print the shelf.
    
    
            // TODO: Create a shelf to store famous integers:
            //       13, 23, 42, 1729,
            // TODO: Then print the shelf.
    
    
        }
    }
    

    Reveal Solution

  12. Consider the following code snippets for a LinkedList you may implement and a main method:

    public class LinkedList {
       private class Node {
          int data;
          Node next;
       }
       Node head;
    
       void add(int data);
       int get(int idx);
       //...   
    
    public class TestingLinkedList {
      public class static main(String args[]) {
         LinkedList ll = new LinkedList();
         
         for(int i = 0; i < 100000; i++){
             ll.add(i * 3);
         }
         
         for(int i = 0; i < 100000; i++){
             System.out.println("" + ll.get(i)); //<-- MARK
         }
      }
    }
    
    

    Explain why the line with MARK is extremely inefficient? Use Big-O to explain.

    Reveal Solution

  13. Continuing with the example above, explain why expanding LinkedList to implement Iterable solves the inefficiency problem you described above.

    Reveal Solution

  14. Finish the main method below to use the fibonacci iterator to print out the sequence: 1 2 3 5 8 13 21 ...

    import java.util.Iterator;
    
    class Fibonacci implements Iterable<Integer> {
        public static void main(final String args[]) {
            Fibonacci fibonacci = new Fibonacci(21);
    
            // TODO:  Use the fibonacci iterator to print out the sequence: 1 2 3 5 8 13 21
        }
    
        private int max;
    
        public Fibonacci(int max) {
            this.max = max;
        }
    
        public Iterator<Integer> iterator() {
            return new FibonacciIterator();
        }
    
        private class FibonacciIterator implements Iterator<Integer> {
            int current = 1;
            int previous = 0;
    
            @Override
            public boolean hasNext() {
                return current + previous <= max;
            }
    
            @Override
            public Integer next() {
                int tmp = current;
                current += previous;
                previous = tmp;
                return current;
            }
        }
    }
    

    Reveal Solution

  15. Explain why the Comparable interface is an interface rather than class?

    Reveal Solution

  16. Add the compareTo method in the Car class above. So that the main method will print out:

    Name: Lamborghini Top Speed: 225
    Name: Porsche Top Speed: 202
    Name: Mustang Top Speed: 144
    Name: Jeep Top Speed: 110
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class Car implements Comparable<Car> {
        public static void main(String[] args) {
            List<Car> carsList = new ArrayList<>();
            carsList.add(new Car("Porsche", 202));
            carsList.add(new Car("Jeep", 110));
            carsList.add(new Car("Mustang", 144));
            carsList.add(new Car("Lamborghini", 225));
    
            Collections.sort(carsList);
            for(Car car : carsList) {
                System.out.println("Name: " + car.getName() + " Top Speed: " + car.getTopSpeed());
            }
        }
        private String name;
        private Integer topSpeed;
    
        public Car(String name, Integer topSpeed) {
            this.name = name;
            this.topSpeed = topSpeed;
        }
    
        public String getName() {
            return name;
        }
    
        public Integer getTopSpeed() {
            return topSpeed;
        }
    
        // TODO: Complete the Car class by adding the compareTo method
        //       needed to correctly implement Comparable<Car>.
    
    }
    
    

    Reveal Solution