Started making our Zoo dynamic:
add(...) new animalsremove(...) animals from the collectioncontains(...) an animalAlso:
feedAnimalsRepresent Zoo as a linked list of Nodes:


Node

tail.next

tail

Animal in Code // add an Animal to the zoo
public void add (Animal a) {
Node nd = new Node(a);
if (tail != null) {
tail.setNext(nd);
tail = nd;
} else {
head = nd;
tail = nd;
}
}
feedAnimals?
contains?
remove?
With the array Animal[] zoo we could access all of the Animals easily:
Animal[] zoo;
...
for (int i = 0; i < zoo.length; i++) {
// do something with zoo[i]
}
How could we do something similar with the Zoo class?
Zoo
next() that:
null)
null, gohasNext() to check if there is a next animal(We will see a more elegant way using iterators later…)
The logic and structure of our Zoo is great!
But what if we want to store things other than Animals?



How could we represent a list of anything?
Object

public class ListOfObjects {
private Node head = null;
private Node tail = null;
public void add (Object obj) {
...
}
public void remove (Object obj) {
...
}
public boolean contains (Object obj) {
...
}
public Object next () {
...
}
}
class Node {
private Object obj;
private Node next;
public Node (Object obj) {
this.obj = obj;
next = null;
}
public void setNext (Node nd) {
next = nd;
}
public Node getNext () {
return next;
}
public Object getObj () {
return obj;
}
}
ListOfObjects list = new ListOfObjects();
list.add(new Elephant("Alice"));
...
ListOfObjects list = new ListOfObjects();
list.add(new Elephant("Alice"));
...
Casting! Every time we access something in the list, it must be cast as the correct type:
Animal a = (Animal) list.next()
This is annoying…
ListOfObjects list = new ListOfObjects();
list.add(new Elephant("Alice"));
...
There is nothing requiring us to use the same datatype
list.add(new Platypus("Bob"));
list.add("Adding a String now");
list.add(Integer.getInteger("3745"));
These operations are perfectly valid!
Idea: Write a GenericList class that
Declare class with a type, T:
public class GenericList<T> {
...
}
Inside the class, T can be used like a variable representing the type:
// add an item of type T
public void add (T item) {
...
}
// get next item of type T
public T next () {
...
}
Node
Node generic:
class Node<T> {
private T item;
private Node<T> next;
...
}
Node an inner class:
public class GenericList<T> {
...
class Node {
private T item;
private Node<T> next;
...
}
}
// make lists storing different types
GenericList<Animal> zoo = new GenericList<Animal>();
GenericList<Person> amherst = new GenericList<Person>();
// populate the lists
zoo.add(new Platypus("Alice"));
amherst.add(new Person("Bob"));
...
// these give errors!
amherst.add(new Elephant("Eve"));
zoo.contains("Bob");