Generalized Containers CSIS 3701: Advanced Object Oriented Programming
Dec 31, 2015
Generalizing Containers
• Example: Stack class that stores strings
public class Stack {
private String[] contents;
private int top;
public Stack(int s) {
contents = new String[s];
top = 0;
}
public void push(String x) {contents[top++] = x;}
public String pop() {return contents[--top];}
Generalizing Containers
• Problem: Need different stack class for different types of contents
public class IntStack {
private Integer[] contents;
…
public class EmployeeStack {
private Employee[] contents;
…
Generalizing Containers
• Goal: one stack class that can store any type of contents
public class Stack {
private anything[] contents;
• Tools:– Polymorphism: Can assign subclass object to
superclass variable
– Java hierarchy: All Java objects have Object class as ultimate superclass
• Key: Can assign any Java object to a variable of type Object
Containers of Objects
• Use Object as type stored by container
public class Stack {
private Object[] contents;
private int top;
public Stack(int s) {
contents = new Object[s];
top = 0;
}
public void push(Object x) {contents[top++] = x;}
public Object pop() {return contents[--top];}
Containers of Objects
• Example:
Stack stooges = new Stack(4);
Stooges.push(“Larry”);
Stooges.push(“Curley”);
Stooges.push(“Moe”);
public class Stack {
public void push(Object x) {contents[top++] = x;}
private Object[] contents;
Storing String objects in Object array
Limits of Containers of Objects
• Inspector methods return Object type instead of original type stored
• Will cause error if assigned to variable of original type
stooges.push(“Moe”);String name = stooges.pop();
• Must explicitly cast back to original type:
String name = (String)stooges.pop();
Object
Type mismatch error!
Limits of Containers of Objects
• Cannot store simple types in containers– Store in type wrappers
stooges.push(new Integer(3));
– Is done automatically by later versions of Java
• Can store multiple types of object in single container
stooges.push(“Larry”);stooges.push(3);stooges.push(new Clock());
– Problem if must cast back to original type – what was it?
Java Container Classes
• Java provides many built-in generalized containers– Stack, Queue, Hashtable, …– In java.util.*
• All implemented by storing Object elements
• Most used container type: ArrayList– Can access elements by index (like array)– Can insert/remove elements (like linked list)– Can grow dynamically (like linked list)– Has built-in search
ArrayList Class
• “Array” type methods:
– public void set(int index, Object x); store x in indexth element
– public Object get(int index); return object at indexth element
• Will need to cast back to original type• Throws ArrayIndexOutOfBoundsException if index illegal
– public int size();
ArrayList Class
• “Linked list” type methods:
– public void add(Object x); add x to end of list
– public void add(int index, Object x); insert x at indexth element (shifting others to right)
– public Object remove(int index); remove object at indexth element (shifting others to left) and return it
ArrayList Class
• “Search” type methods:
– public boolean contains(Object x); returns true if x in list
– public void indexOf(Object x); return index of first occurrence of x (or -1 if x not in list)
– public void indexOf(Object x, int index);
return index of first occurrence of x starting at index
• Based on equals method for object x
ArrayList Example
• Rewrite of NameList to use ArrayList – no maximum since list grows dynamically– no current, since can add dynamically to end
public class NameList {
private ArrayList names; // List of names stored
public NameList() {
names = new ArrayList();
}
ArrayList Example
• Use “linked list” method to add new name to end• Use search to make sure not already in list
public void add(String name) throws InListException {
if (names.contains(name)) throw new InListException();
names.add(name);
}
• Use “array” method to iterate through list (casting back to original type)
public String toString() {
String result = "";
for (int i = 0; i < names.size(); i++)
result += (String)names.get(i)+",";
return result;
}
Object Equality
• Java containers use equals method for search
public boolean contains(Object x) { for (int i = 0; i < size(); i++) if x.equals(get(i)) return true; return false;
• May need to override equals in your classes if–Store in container–Search for equivalent objects (perhaps to avoid duplication)
• Will need to define what it means for two objects to be “equivalent”
Object Equality
• Built-in equals method takes an Object as parameter– Must check type of parameter first using instanceof operator– Then cast to appropriate type before comparing relevant fields
• Basic form of a equals method for some class C:
public boolean equals(Object x) { if (this == x) return true; if (x instanceof C) { C y = (C)x; compare relevant fields, returning either true or false
} return false;}
Do they refer to the same object?
Is it the same type as C?
If so, cast to class C and compare relevant fields
Object Equality
• Example: equals for Employee class– Define as equivalent if have same name
public boolean equals(Object x) {
if (this == x) return true;
if (x instanceof Employee) {
Employee e = (Employee)x;
return name.equals(e.name);
}
return false;
}
Generics (Templates)
• Containers with type checking– Define generically: stores object of “type <T>”
public class classname<T> {…
– Define the actual type when specific object created
classname variable<actual type> = new classname();
– Originated by C++– Recently implemented (in limited form) in Java
Defining Generics
• Example: Pair class – Stores two different values of same type– Type determined when object constructed
public class Pair<T> {
private T thing1, thing2;
public Pair() {
thing1 = thing2 = null;
}
Stores two variables, both of type T
Defining Generics
public class Pair<T> {…
public void set(T value, int which) {
if (which == 1) thing1 = value;
if (which == 2) thing2 = value;
}
public T get(int which) {
if (which == 1) return thing1;
if (which == 2) return thing2;
return null;
}
Methods take/return values of generic type T
Using Generics
• Define actual type stored when object declared
Pair<String> p1 = new Pair();
p1.set("Fred", 1);
p1.set("Barney", 2);
String name = p1.get(1);
• Note that do not need to cast back to original type – compiler now knows original type
Using Generics
• Can create generics of different types
Pair<Integer> p2 = new Pair();
p2.set(12, 1);
p2.set(13, 2);
int x = p2.get(1);
p2.set(“Fred”, 1);
• Unlike polymorphism, Java does type checking
Limits of Generics
• Java does not allow arrays to be used with generics– This is legal in C++!
public class StackTemplate<T> {
private T[] contents;
private int top;
public StackTemplate(int s) {
contents = new T[s];
top = 0;
Compiler error
Generics and Java Containers
• Many Java containers upgraded to use generics• Example: Vector class
ArrayList a<String> = new ArrayList();
a.add(“Larry”);
a.add(3);
ArrayList that only contains Strings
This is legal
This is not
Generics and Java Containers
• Can use generic containers to define your own containers– Example: Generic Stack class that uses generic ArrayList
class
public class StackTemplate<T> {
private ArrayList<T> contents;
public StackTemplate() {contents = new ArrayList();}
public void push(T x) {contents.add(x);}
public T pop() {
return contents.remove(contents.size()-1);
}
}