So far in class, we have been implementing simplified data structures in Java that only hold `int`

s (e.g. `ArrayIntList`

, `IntTree`

). This reading will explore the idea of **generics** that allows you to write classes that can hold any type the user wants! The final goal will be turning our `IntTree`

into a `TreeSet<E>`

such that it can hold any type that can be sorted. Before we do that, we start with a simplified generics example.

## Pair¶

Suppose I wanted to write a `Pair`

class that represents a pair of values. With what we have seen so far, we might define the class to only hold `int`

s, like in the example below.

```
public class IntPair {
private int first;
private int second;
public IntPair(int first, int second) {
this.first = first;
this.second = second;
}
public int getFirst() {
return first;
}
public int getSecond() {
return second;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}
```

To construct this `IntPair`

I would write something like:

```
IntPair p = new IntPair(1, 2);
```

This is all well and good, but what if I want a pair of `String`

s instead? I could write a new class called `StringPair`

, which we have shown below.

```
public class StringPair {
private String first;
private String second;
public StringPair(String first, String second) {
this.first = first;
this.second = second;
}
public String getFirst() {
return first;
}
public String getSecond() {
return second;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}
```

To construct this `StringPair`

I would write something like:

```
StringPair p = new StringPair("a", "b");
```

This is a pretty ridiculous approach to solving this problem since it would require duplicating this class for every possible type of pair values in Java. These classes are exactly the same besides what the type is for the `first`

and `second`

values. It would be nicer if I could write a single `Pair`

class that is more **generic** in the sense it can hold any type of data!

### Enter Type Parameters¶

Java 5 introduced this really nifty feature that allows you to have a class accept a type parameter in order to make it more generic. The type parameter lets you write one version of your class that can work with any type of object that it will store. To specify a type parameter, you use this `<E>`

syntax in the class name. We start by showing a generic `Pair<E>`

class below and then we explain what this does.

```
public class Pair<E> {
private E first;
private E second;
public Pair(E first, E second) {
this.first = first;
this.second = second;
}
public E getFirst() {
return first;
}
public E getSecond() {
return second;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}
```

How would you now construct one of these `Pair<E>`

? You have to specify the type when you construct it!

```
Pair<Integer> p1 = new Pair<Integer>(1, 2); // Notice Integer, not int
Pair<String> p2 = new Pair<String>("a", "b");
```

What have we done here? We have made a `Pair`

class that is generic: it takes a type parameter `E`

that indicates what type of value it will hold and replaces all instances of a specific value type with this `E`

. In some sense, `E`

is just a place-holder type for any type someone might make a pair of (in the example above: for `p1`

, `E`

is `Integer`

and for `p2`

, `E`

is `String`

). You can think of it as, when you make a `Pair<Scanner>`

it goes ahead and makes a new class based on `Pair<E>`

, but all the `E`

s are replaced by `Scanner`

!

This is helpful because you only need to write a single `Pair`

object and it can be used in many different contexts!

### Interlude: What about `Object`

?¶

You might be thinking there is another way to solve this problem:

Forget type parameters, I’ll just use this

`Object`

class that is a super-class of all classes!

In this section, we will ignore everything we have just seen about these type parameters and try to solve this problem without them. For example, you could write the class below without using type parameters.

```
public class ObjectPair {
private Object first;
private Object second;
public ObjectPair(Object first, Object second) {
this.first = first;
this.second = second;
}
public Object getFirst() {
return first;
}
public Object getSecond() {
return second;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}
```

And then when you wanted to construct it, you could write something like the following.

```
ObjectPair p3 = new ObjectPair(1, 2);
ObjectPair p4 = new ObjectPair("a", "b");
```

This is actually not a bad idea since this is how we had to write generic classes before the advent of Java 5. However, we’ll see this causes some problems later on, when we want to use the values inside the instance. For example, what if you wanted to call the `getFirst`

method on `p4`

and print out the upper case version of that `String`

? You might try to write something like:

```
System.out.println(p4.getFirst().toUpperCase()); // causes a compiler error
```

This doesn’t work because Java doesn’t know the return type of `p4.getFirst()`

is a `String`

! All it knows is it’s an `Object`

which means any type could actually be in there (i.e. the `PromiseType`

is `Object`

). With what we saw from the inheritance lesson, you could get around this by using casting to tell Java to chill since you know the value is actually a `String`

, but this is error prone since many casting errors can’t be checked at compile time.

This awkwardness with casting is essentially the whole reason type parameters exist! With generics, you can guarantee at compile-time that if you call `p1.getFirst()`

(recall `p1`

is type `Pair<Integer>`

), you know it’s return type will be `Integer`

so you never have to cast.

### Multiple Type Parameters¶

In some applications, it makes sense to make your class be generic with multiple type parameters. You can add more than one type parameter by putting a comma separated list of type parameter names. For example, below we show a `Pair2<E1, E2>`

class that can have different types for the first and second value.

```
public class Pair2<E1, E2> {
private E1 first;
private E2 second;
public Pair2(E1 first, E2 second) {
this.first = first;
this.second = second;
}
public E1 getFirst() {
return first;
}
public E2 getSecond() {
return second;
}
public String toString() {
return "(" + first + ", " + second + ")";
}
}
```

This can be useful in some cases for more complicated classes. The intuition is the same, but now you can have differing types. If you made a `Pair2<String, Integer>`

, you would know that `getFirst`

returns a `String`

while `getSecond`

returns an `Integer`

.

## Make `TreeSet<E>`

¶

With everything we have seen so far, we are ready to tackle turning `IntTree`

into `TreeSet<E>`

. Below we show the whole class which is the same as the `IntTree`

we ended with two weeks ago except: * We have renamed it to `TreeSet`

* We have made it generic so it now takes a type parameter `E`

. This means every place we used `int`

, we know use this generic `E`

value. This means we have renamed `IntTreeNode`

to `TreeNode<E>`

as well!

This looks complicated at first, but notice it’s exactly the same class with just these find/replace operations described above!

```
// This class represents a binary search tree of any type
// A binary search tree is one that every value to the left of a value is less
// than it, and every value to the right is greater than it. Duplicates are not allowed.
public class TreeSet<E> {
private TreeNode<E> overallRoot;
// Constructs a tree with no numbers
public TreeSet() {
overallRoot = null;
}
// Returns true if the value is in this tree, false otherwise
public boolean contains(E value) {
return contains(overallRoot, value);
}
// Returns true if the given value is contained in the tree
// rooted at the given root, false otherwise
private boolean contains(TreeNode<E> root, E value) {
if (root == null) {
return false;
} else if (root.data == value) {
return true;
} else if (value < root.data) {
return contains(root.left, value);
} else { // value > root.data
return contains(root.right, value);
}
}
// pre: This is a binary search tree
// post: Adds the value to the tree such that
// it maintains the binary search tree property
public void add(E value) {
overallRoot = add(overallRoot, value);
}
// pre: the subtree rooted at `root` is a binary search tree
// post: adds the given value to the subtree rooted at
// `root` such that it preserves the binary search tree
// property
private TreeNode<E> add(TreeNode<E> root, E value) {
if (root == null) {
root = new TreeNode<E>(value);
} else if (value < root.data) {
root.left = add(root.left, value);
} else if (value > root.data) {
root.right = add(root.right, value);
}
return root;
}
// Returns the number of numbers in this tree.
public int size() {
return size(overallRoot);
}
// Returns the number of nodes in the tree starting at root.
private int size(TreeNode<E> root) {
if (root == null) {
return 0;
} else {
int leftSize = size(root.left);
int rightSize = size(root.right);
return 1 + leftSize + rightSize;
}
}
// Class that represents a single node in the tree
private static class TreeNode<E> {
public E data; // data stored at this node
public TreeNode<E> left; // reference to left subtree
public TreeNode<E> right; // reference to right subtree
// Constructs a leaf node with the given data.
public TreeNode(E data) {
this(data, null, null);
}
// Constructs a leaf or branch node with the given data and links.
public TreeNode(E data, TreeNode<E> left, TreeNode<E> right) {
this.data = data;
this.left = left;
this.right = right;
}
}
}
```

Unfortunately, this class doesn’t work as written! It’s pretty close, but there is one pretty big flaw that has to do with how we do the “less than” or “greater than” checks! Remember, `<`

or `>`

only work for numeric types like integers or doubles. Inside our class, we have no idea what type `E`

is! This means, it can be any `Object`

type so there is no guarantee you can use `<`

or `>`

to compare them!

How do we compare objects that aren’t numeric types in Java? We have to make sure they implement the `Comparable<E>`

interface so that we are sure they have a `compareTo(E)`

method!

The first thing we need to do to accomplish this is enforce that the type `E`

implements the `Comparable<E>`

interface. The syntax for this looks a bit weird, but you can put restrictions on what types are valid for a type parameter using the syntax shown below.

```
public class TreeSet<E extends Comparable<E>> {
...
}
```

What this is saying is that the only types that are allowed inside the `TreeSet`

are types that implement the `Comparable<E>`

of interface. This means `TreeSet<String>`

is allowed, but `TreeSet<List<String>>`

is not since `List<String>`

is not comparable. Confusingly, you use the `extends`

keyword in type parameters to put these restrictions, even though `Comparable<E>`

is an interface.

The second thing we need to accomplish is replacing all of the `<`

, `>`

, and `==`

in our code with calls on `compareTo`

. Below we just show the `contains`

method and then show the full class at the bottom. All this method is doing is just using `compareTo`

as we learned about so that we are able to figure out if `value`

comes before or after `root.data`

in the sorted ordering; the logic is exactly the same but the mechanics of how you do the check differ.

```
// Returns true if the value is in this tree, false otherwise
public boolean contains(E value) {
return contains(overallRoot, value);
}
// Returns true if the given value is contained in the tree
// rooted at the given root, false otherwise
private boolean contains(TreeNode<E> root, E value) {
if (root == null) {
return false;
} else if (root.data.compareTo(value) == 0) {
return true;
} else if (value.compareTo(root.data) < 0) { // value < root.data
return contains(root.left, value);
} else { // value > root.data
return contains(root.right, value);
}
}
```

Below, we show the fully generic `TreeSet<E>`

with correct comparison tests

```
// This class represents a binary search tree of any type
// A binary search tree is one that every value to the left of a value is less
// than it, and every value to the right is greater than it. Duplicates are not allowed.
public class TreeSet<E extends Comparable<E>> {
private TreeNode<E> overallRoot;
// Constructs a tree with no numbers
public TreeSet() {
overallRoot = null;
}
// Returns true if the value is in this tree, false otherwise
public boolean contains(E value) {
return contains(overallRoot, value);
}
// Returns true if the given value is contained in the tree
// rooted at the given root, false otherwise
private boolean contains(TreeNode<E> root, E value) {
if (root == null) {
return false;
} else if (root.data.compareTo(value) == 0) {
return true;
} else if (value.compareTo(root.data) < 0) { // value < root.data
return contains(root.left, value);
} else { // value > root.data
return contains(root.right, value);
}
}
// pre: This is a binary search tree
// post: Adds the value to the tree such that
// it maintains the binary search tree property
public void add(E value) {
overallRoot = add(overallRoot, value);
}
// pre: the subtree rooted at `root` is a binary search tree
// post: adds the given value to the subtree rooted at
// `root` such that it preserves the binary search tree
// property
private TreeNode<E> add(TreeNode<E> root, E value) {
if (root == null) {
root = new TreeNode<E>(value);
} else if (value.compareTo(root.data) < 0) { // value < root.data
root.left = add(root.left, value);
} else if (value.compareTo(root.data) > 0) { // value > root.data
root.right = add(root.right, value);
}
return root;
}
// Returns the number of numbers in this tree.
public int size() {
return size(overallRoot);
}
// Returns the number of nodes in the tree starting at root.
private int size(TreeNode<E> root) {
if (root == null) {
return 0;
} else {
int leftSize = size(root.left);
int rightSize = size(root.right);
return 1 + leftSize + rightSize;
}
}
// Class that represents a single node in the tree
private static class TreeNode<E> {
public E data; // data stored at this node
public TreeNode<E> left; // reference to left subtree
public TreeNode<E> right; // reference to right subtree
// Constructs a leaf node with the given data.
public TreeNode(E data) {
this(data, null, null);
}
// Constructs a leaf or branch node with the given data and links.
public TreeNode(E data, TreeNode<E> left, TreeNode<E> right) {
this.data = data;
this.left = left;
this.right = right;
}
}
}
```

## Generic Collections¶

Below, we link all of the files we worked on class today but with their generic versions.