This lecture has changed significantly since last semester; because generics (type parameters) have been added to Java, and in particular to the container classes.
The goal of this lecture is to make you familiar with the container classes in Java, and give you some hints on how to use them. And in particular to let you understand the usage of Generics in the container libraries. We will try to keep the container concepts free from the generics at first.
We assume that you are already familiar with the array-types in Java, and know how to use arrays for storing and retrieving object references and primitive types. But in many ways the functionality of arrays is too limited.
Besides arrays, Java therefore also has a library of container classes. The figure on page 92 in JP (and in the slides) gives you a graphical overview of these. The container classes have different strengths and have been designed for different purposes. So instead of just using an array every time you need a container, you now have to make a choice between different containers. The purpose of this lecture and the excercises is to give you some knowledge of what would be the best choise in different situations.
To make such a choise it is necessary to have some basic understanding of the data structures that the container classes represent, and the algorithms that work on these structures. The lecture will aim to give you a "crash course" on this subject. In section 22.10 there is a figure which illustrates the time complexity of the most common operations on different Collections - the figure might be difficult to understand at first, but hopefully the lecture will make it a bit clearer why some Collections are faster at some operations than others.
For this excercise you will have to use the class Story.java, which is an example program that you can find on the homepage. The class has a method getTextAsLinkedList(), which returns a text broken into words, which have been added to a LinkedList. (If you like to you can try to run the main method of the Story class, to see how the story has been broken into words.)
Write a class CollectionTest.java with a main method where you can try out the different things you are asked to do in this excercise. Remember to use an Iterator when you have to traverse the Collections. You can use typeparameters if you wish, but that is not the point of this exercise.
Write a new class with a main method. The rest of the exercise can be done by adding code fragments to this main method. You will need access to the Person and Student classes below:
class Person { String name; Integer birthYear; Person(String name, int birth){ this.name = name; birthYear = birth; // boxing } Integer age(){ return 2004-birthYear; // unboxing & boxing } } class Student extends Person{ String university; Student(String name, int birth){ super(name, birth); university = "ITU"; } Student(String name, int birth, String university){ super(name, birth); this.university = university; } }
Declare a List<? extends Person> lep.
Without type parameters, the class Store could look like thisimport java.util.*; public class Store{ private List goods; public Store() { goods = new ArrayList (); } public void add(Object obj){ goods.add(obj); } public Object remove(){ return goods.remove(goods.size()-1); } }
- Add a type parameter T to Store, so that the generic class Store can be instantiated like Store<Bicycle> or Store<Goods>, but not Store<String>. Change body of the class so that appropriate fields, parameters and return types use the new parameter T. Did you have to change anything in the body of the methods?
- The Goods and Bicycle classes could be defined as:
public class Goods{ private String description; public Goods(String desc){ description = desc; } public String toString(){ return description; } } public class Bicycle extends Goods{ public Bicycle(String s){ super(s); } }Test that the typeparameters you added in a) works in the following example main method:
public static void main(String[] args){ Store<Bicycle> bStore = new Store<Bicycle>(); Bicycle big = new Bicycle("big"); Bicycle small = new Bicycle("Small"); bStore.add(big); bStore.add(small); Bicycle b = bStore.remove(); System.out.println(b); }- Add a method public void addAll(Collection< whatToWriteHere > c) to Store. The method should add all the elements in c to the goods List. There are really two parts to this exercise, to figure out type expression should be used instead of whatToWriteHere, and the implementation of the method body. It should be so that if the store is a general Goods store, you should be able to add a collection of Bicycles. That is, the following call should be possible:
Store<Goods> generalStore = new Store<Goods>(); generalStore.addAll(new ArrayList()); - (Hard and optional). Now, we want a method which can sell all elements from the store. Rather than returning a collection of all the elements, we pass a collection c as parameter, and the method should place all the elements in the Store in c. The method could be implemented as:
public void sellAll(Collection<T> buyer){ for(T elm:goods) buyer.add(elm); } But the following call should be possible.
Store<Bicycle> bStore = new Store<Bicycle>(); Collection<Goods> g = new ArrayList<Goods>(); bStore.sellAll(g);What should one write instead of T and why?