Lecture 13 - 02/15

Generics, Conversion, Promotion, Covariance

Generics:

Below is a demonstration of using the ArrayList class that takes in a generic data type (in this case, String):

ArrayList<String> L = new ArrayList<String>();

Immutability:

ArrayMap

First, we create a Map61B interface in a Map61B package/folder:

package Map61B;
import java.util.List;
public interface Map61B<K, V> {
/* Returns true if this map contains a mapping for the specified key. */
boolean containsKey(K key);
/* Returns the value to which the specified key is mapped. No defined
* behavior if the key doesn't exist (ok to crash). */
V get(K key);
/* Returns the number of key-value mappings in this map. */
int size();
/* Associates the specified value with the specified key in this map. */
void put(K key, V value);
/* Returns a list of the keys in this map. */
List<K> keys();
}

Now we make the ArrayMap class, that implements Map61B. The class also has some JUnit tests:

package Map61B;
import org.junit.Assert.*;
import java.util.List;
import java.util.ArrayList;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* An array based implementation of the Map61B class.
*/
public class ArrayMap<K, V> implements Map61B<K, V> {
private K[] keys;
private V[] values;
int size;
public ArrayMap() {
keys = (K[]) new Object[100];
values = (V[]) new Object[100];
size = 0;
}
/** Returns the index of the given key if it exists,
* -1 otherwise. */
private int keyIndex(K key) {
for (int i = 0; i < size; i += 1) {
if (keys[i].equals(key)) {
return i;
}
}
return -1;
}
public boolean containsKey(K key) {
int index = keyIndex(key);
return index > -1;
}
public void put(K key, V value) {
int index = keyIndex(key);
if (index == -1) {
keys[size] = key;
values[size] = value;
size += 1;
return;
}
values[index] = value;
}
public V get(K key) {
int index = keyIndex(key);
return values[index];
}
public int size() {
return size;
}
public List<K> keys() {
List<K> keylist = new ArrayList<K>();
for (int i = 0; i < keys.length; i += 1) {
keylist.add(keys[i]);
}
return keylist;
}
@Test
public void test() {
ArrayMap<Integer, Integer> am = new ArrayMap<Integer, Integer>();
am.put(2, 5);
int expected = 5;
assertEquals((Integer) expected, am.get(2));
}
public static void main(String[] args) {
ArrayMap<String, Integer> m = new ArrayMap<String, Integer>();
m.put("horse", 3);
m.put("fish", 9);
m.put("house", 10);
}
}

Generic Methods

Lastly, we create a class MaxHelper:

package Map61B;
import static org.junit.Assert.*;
import org.junit.Test;
import java.util.List;
/**
* Class to demonstrate how generic methods work in Java.
*/
public class MapHelper {
/* Write the following three methods:
/* get(Key) : Return item in map if it exists. */
public static <K, V> V get(Map61B<K, V> sim, K key) {
if (sim.containsKey(key)) {
return sim.get(key);
}
return null;
}
/* maxKey() : Returns max of all keys. Works only if x and y have comparable data. */
public static <K extends Comparable<K>, V> K maxKey(Map61B<K, V> map) {
List<K> keylist = map.keys();
K largest = keylist.get(0);
for (K k : keylist) {
if (k.compareTo(largest) > 0) {
largest = k;
}
}
return largest;
}
/* allBark(): Makes all keys bark. Works only for keys of type Dog. */
public static void allBark(ArrayMap<Dog, ?> am) {
for (Dog d : am.keys()) {
d.bark();
}
}
@Test
public void testGet() {
Map61B<String, Integer> m = new ArrayMap<String, Integer>();
m.put("horse", 3);
m.put("fish", 9);
m.put("house", 10);
Integer actual = MapHelper.get(m, "fish");
Integer expected = 9;
assertEquals(expected, actual);
assertEquals(null, MapHelper.get(m, "awefawefawef"));
}
@Test
public void testMaxKey() {
Map61B<String, Integer> m = new ArrayMap<String, Integer>();
m.put("horse", 3);
m.put("fish", 9);
m.put("house", 10);
String actual = MapHelper.maxKey(m);
String expected = "house";
assertEquals(expected, actual);
}
}

Covariance: