Started making our Zoo
dynamic:
add(...)
new animalsremove(...)
animals from the collectioncontains(...)
an animalAlso:
feedAnimals
Represent Zoo
as a linked list of Node
s:
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 Animal
s 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 Animal
s?
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");