public void add(E element) public E get(int index)
ArrayList<BankAccount> ArrayList<Measurable>
ArrayList<double> // Wrong!
ArrayList<Double>
public void add(BankAccount element)
public void add(Object element)
ArrayList<BankAccount> accounts1 = new ArrayList<BankAccount>();
LinkedList accounts2 = new LinkedList(); // Should hold BankAccount objects
accounts1.add("my savings"); // Compile-time error
accounts2.add("my savings"); // Not detected at compile time
. . .
BankAccount account = (BankAccount) accounts2.getFirst(); // Run-time error
ArrayList<Integer> a = new ArrayList<>(); String s = a.get(0);
ArrayList<Double> a = new ArrayList<>(); a.add(3);
LinkedList a = new LinkedList(); a.addFirst("3.14"); double x = (Double) a.removeFirst();
Pair<String, Integer> result = new Pair<>("Harry Hacker", 1729);
String name = result.getFirst(); Integer number = result.getSecond();
public class Pair<T, S>
Type Variable | Meaning |
E | Element type in a collection |
K | Key type in a map |
V | Value type in a map |
T | General type |
S, U | Additional general types |
public class Pair<T, S>
public class Pair<T, S> { private T first; private S second; public Pair(T firstElement, S secondElement) { first = firstElement; second = secondElement; } public T getFirst() { return first; } public S getSecond() { return second; } }
Diana Expected: Diana 1 Expected: 1
public static Pair<Double, Double> roots(Double x) { if (x >= 0) { double r = Math.sqrt(x); return new Pair<Double, Double>(r, -r); } else { return null; } }
public class ArrayUtil { /** Prints all elements in an array. @param a the array to print */ public <T> static void print(T[] a) { . . . } . . . }
public class ArrayUtil { public static void print(String[] a) { for (String e : a) { System.out.print(e + " "); } System.out.println(); } . . . }
public static <E> void print(E[] a) { for (E e : a) { System.out.print(e + " "); } System.out.println(); }
Rectangle[] rectangles = . . .; ArrayUtil.print(rectangles);
public static <T> void fill(List<T> lst, T value)
{
for (int i = 0; i < lst.size(); i++) { lst.set(i, value); }
}
If you have an array list
ArrayList
<String>
a = new ArrayList<String>(10);
how do you fill it with ten "*"?
public static <T> fill(T[] arr, T value)
{
for (int i = 0; i < arr.length; i++) { arr[i] = value; }
}
What happens when you execute the following statements?
String[] a = new String[10]; fill(a, 42);
You can place restrictions on the type parameters of generic classes and methods.
public interface Measurable { double getMeasure(); }
public static <E extends Measurable> double average(ArrayList<E> objects)
public static <E extends Measurable> double average(ArrayList<E> objects)
{
if (objects.size() == 0) { return 0; }
double sum = 0;
for (E obj : objects)
{
sum = sum + obj.getMeasure();
}
return sum / objects.size();
}
public interface Comparable<T> { int compareTo(T other); }
public static <E extends Comparable<E>> E min(ArrayList<E> objects)
{
E smallest = objects.get(0);
for (int i = 1; i < objects.size(); i++)
{
E obj = objects.get(i);
if (obj.compareTo(smallest) < 0)
{
smallest = obj;
}
}
return smallest;
}
int compareTo(E other)
obj.compareTo(smallest)
<E extends Comparable<E> & Cloneable>
extends or implements.
public class BinarySearchTree<E extends Comparable<E>>
or, if you read Special Topic 18.1,
public class BinarySearchTree<E extends Comparable<? super E>>
public static <E extends Measurable> E min(ArrayList<E> objects)
{
E smallest = objects.get(0);
for (int i = 1; i < objects.size(); i++)
{
E obj = objects.get(i);
if (obj.getMeasure() < smallest.getMeasure())
{
smallest = obj;
}
}
return smallest;
}
public static Measurable min(ArrayList<Measurable> a)
public static Measurable min(Measurable[] a)
public static <E extends Measurable> double average(E[] objects)
{
if (objects.length == 0) { return 0; }
double sum = 0;
for (E obj : objects)
{
sum = sum + obj.getMeasure();
}
return sum / objects.length;
}
public static double average(Measurable[] objects) { if (objects.length == 0) { return 0; } double sum = 0; for (Measurable obj : objects) { sum = sum + obj.getMeasure(); } return sum / objects.length; }For example, if BankAccount implements Measurable, a BankAccount[] array is convertible to a Measurable[] array. Contrast with Self Check 19, where the return type was a generic type. Here, the return type is double, and there is no need for using generic types.
ArrayList<SavingsAccount> savingsAccounts = new ArrayList<SavingsAccount>();
ArrayList<BankAccount> bankAccounts = savingsAccounts;
// Not legal - compile-time error
SavingsAccount[] savingsAccounts = new SavingsAccount[10];
BankAccount bankAccounts = savingsAccounts; // Legal
BankAccount harrysChecking = new CheckingAccount();
bankAccounts[0] = harrysChecking; // Throws ArrayStoreException
Name | Syntax | Meaning |
---|---|---|
Wildcard with lower bound | ? extends B | Any subtype of B |
Wildcard with upper bound | ? super B | Any supertype of B |
Unbounded wildcard | ? | Any type |
public void addAll(LinkedList<? extends E> other) { ListIterator<E> iter = other.listIterator(); while (iter.hasNext()) { add(iter.next()); } }
public static <E extends Comparable<E>> E min(E[] a)
public static <E extends Comparable<? super E>> E min(E[] a)
static void reverse(List<?> list)
static void <T> reverse(List<T> list)
In the Java virtual machine, generic types are erased.
public class Pair
{
private Object first;
private Object second;
public Pair(Object firstElement, Object secondElement)
{
first = firstElement;
second = secondElement;
}
public Object getFirst() { return first; }
public Object getSecond() { return second; }
}
public static <E extends Measurable> E min(E[] objects)
{
E smallest = objects[0];
for (int i = 1; i < objects.length; i++)
{
E obj = objects[i];
if (obj.getMeasure() < smallest.getMeasure())
{
smallest = obj;
}
}
return smallest;
}
public static Measurable min(Measurable[] objects) { Measurable smallest = objects[0]; for (int i = 1; i < objects.length; i++) { Measurable obj = objects[i]; if (obj.getMeasure() < smallest.getMeasure()) { smallest = obj; } } return smallest; }
public static <E> void fillWithDefaults(E[] a) { for (int i = 0; i < a.length; i++) a[i] = new E(); // ERROR }
public static void fillWithDefaults(Object[] a) { for (int i = 0; i < a.length; i++) a[i] = new Object(); // Not useful }
public static <E> void fillWithDefaults(E[] a, E defaultValue)
{
for (int i = 0; i < a.length; i++)
a[i] = defaultValue;
}
public class Stack<E> { private E[] elements; . . . public Stack() { elements = new E[MAX_SIZE]; // Error } }
public class Stack<E> { private ArrayList<E> elements; . . . public Stack() { elements = new ArrayList<E>(); // Ok } . . . }
public class Stack<E>
{
private Object[] elements;
private int currentSize;
. . .
public Stack()
{
elements = new Object[MAX_SIZE]; // Ok
}
. . .
public E pop()
{
size--;
return (E) elements[currentSize];
}
}
public static <E> Comparable<E> min(Comparable<E>[] objects)
is an error. You cannot have an array of a
generic type.public static void print(Object[] a) { for (Object e : a) { System.out.print(e + " "); } System.out.println(); }
public class Stack<E> { private E[] elements; . . . public Stack() { elements = (E[]) new Object[MAX_SIZE]; } . . . }
Object[] toArray()Why doesn't the method return an E[]?
E[] toArray(E[] a)Why can this method return an array of type E[]? (Hint: Special Topic 18.2.)
static <T> T[] copyOf(T[] original, int newLength)be implemented without reflection?