Chapter 17 Review Exercise Solutions
R17.1
Type parameters are variables that can be instantiated with class or interface types.
R17.2
A generic class has one or more type parameters. In order to use a generic class, you need to instantiate the type parameters, that is, supply actual types. Ordinary classes do not use type parameters.
R17.3
A generic class is a class with one or more type parameters. A generic method is a method with one or more type parameters.
R17.4
The toArray method in the java.util.LinkedList class:
public <T> T[] toArray(T[] a)
R17.5
AbstractMap<K,V>
Dictionary<K,V>
EnumMap<K extends Enum<E>,V>
HashMap<K,V>
Hashtable<K,V>
IdentityHashMap<K,V>
LinkedHashMap<K,V>
TreeMap<K,V>
WeakHashMap<K,V>
R17.6
java.lang.Class<T>
java.lang.Enum<T>
java.util.concurrent.Exchanger<V>
java.util.concurrent.ExecutorCompletionService<V>
java.util.concurrent.FutureTask<T>
R17.7
A binary search locates a value in a sorted array by determining whether the value occurs in the first or second half, then repeating the search in one of the halves. To know if the key occurs in the first half or second half, the binary search algorithm needs to be able to determine whether the key is smaller or greater than the middle element. Thus, it needs to use the compareTo method of the Comparable interface.
R17.8
All classes are descendants of the class Object. The class Object has a method to calculate the hash code of an object. Thus, objects of any class can be stored in a hash set.
R17.9
It is an array list of pairs of objects of the same type (e.g. an array list of String pairs).
R17.10
public static <T extends Comparable<? super T>> void sort(List<T> a) means that the type variable T must extend Comparable<U> for some type U where U is any supertype of T (or possibly T itself).
The bound <T extends Comparable> would not have been sufficient. Suppose we want to sort an ArrayList<BankAccount>, where the class BankAccount implements Comparable<BankAccount>. Then we would get a warning. A Comparable object is willing to compare itself against any object, but a BankAccount is only willing to compare against another BankAccount.
public static <T extends Comparable<T>> void sort(List<T> a) does not suffice either because it is still too restrictive. Suppose the BankAccount class implements Comparable<BankAccount>. Then the subclass SavingsAccount also implements Comparable<BankAccount> and not Comparable<SavingsAccount>.
R17.11
We will call the method with the raw ArrayList parameter the “legacy method”. You can pass a parameterized type, such as ArrayList<String> or ArrayList<BankAccount> to the legacy method. This is not completely safe—after all, the legacy method might insert an object of the wrong type. Nevertheless, your program will compile without a warning.
For example, compiling and running the following program does not produce a warning or error:
import java.util.ArrayList;

public class Test
{
   public static void print(ArrayList list)
   {
      for (int i = 0; i < list.size(); i++)
         System.out.println(list.get(i));
   }

   public static void main(String args[])
   {
      ArrayList<String> strList = new ArrayList<String>();
      strList.add("A");
      strList.add("B");
      strList.add("C");
      print(strList);
   }
}

R17.12
We will call the method with the raw ArrayList parameter the “legacy method”.

The code calling the legacy method will compile without a warning. A warning is issued for the legacy method. When the wrong element is inserted, no error happens at that time. When the element with the wrong type is later retrieved, then a ClassCastException occurs.

Consider this example:

import java.util.ArrayList;

public class Test
{
   public static void main(String args[])
   {
      ArrayList<String> strList = new ArrayList<String>();
      strList.add("A");
      strList.add("B");
      strList.add("C");
      doSomethingBad(strList);
      String first = strList.get(0);
   }

   public static void doSomethingBad(ArrayList list)
   {
      list.add(0, new BankAccount(10000));
   }
}

Compiling with the -Xlint:unchecked option yields this warning:

javac -Xlint:unchecked Test.java
Test.java:17: warning: [unchecked] unchecked call to add(int,E) as a
member of the raw type java.util.ArrayList
      list.add(0, new BankAccount(10000));
              ^
We get the following run-time error:

java Test
Exception in thread "main" java.lang.ClassCastException: BankAccount
cannot be cast to java.lang.String
	at Test.main(Test.java:12)
R17.13
Compiling

ArrayList<BankAccount> accounts = new ArrayList<BankAccount>();
if (accounts instanceof ArrayList<String>) System.out.println("true");
else System.out.println("false");

produces the following error:

Test.java [15:1] illegal generic type for instanceof
      if (accounts instanceof ArrayList<String>) System.out.println("true");
                                       ^

The virtual machine that executes Java programs does not work with generic classes or methods. Instead, it uses raw types, in which the type parameters are replaced with ordinary Java types. Each type parameter is replaced with its bound, or with Object if it is not bounded. The compiler erases the type parameters when it compiles generic classes and methods.
At run time, Java uses raw types (e.g. Object or Comparable). Since "accounts instanceof ArrayList<String>" cannot be translated to a run-time raw type, its use is not allowed.
R17.14
You should look for the source code in a directory similar to

C:\Program Files\Java\jdk1.6.0_03\src.zip

and inside the zipped file, under java\util you should find ArrayList.java. Copy this file and look through it. You see immediately that the class contains an array of Object elements (ignore the transient reserved word, it is covered with serialization in Chapter 19). 

private transient Object[] elementData;

There is a constructor:

public ArrayList(Collection<? extends E> c)

The argument is a Collection that inherits from a class of type parameter E. The Collection elements are placed into the Object array by using the following:

elementData = c.toArray();

It is expected that the toArray method will return an Object array. If the conversion doesn’t happen correctly, it compensates by coercing it with a copy and specifying the original class.

if (elementData.getClass() != Object[].class)
   elementData = Arrays.copyOf(elementData, size, Object[].class);