CSC302 2006S, Class 23: Java Generics Admin: * Readings for Friday (separate comments for each) * Finish Beyond Java * Generics in Java * Notes on Stroustrup * Missing: Ventresca, Tasev, Leach Overview: * Weaknesses in Java's "Strong" Type Checking * A Solution: Java Generics * Additional Details * Limiting Parameter Types * Some Subtleties * Behind the Scenes /Notes on S/ * S says objects are good because * Objects help you organize your program * Easier to keep track of stuff * Can more accurately represent the problem (simulation) * Type checking avoids errors * Clearly modularize control * S worries that some object-oriented languages (Simula) are inefficient /Typing in Java/ * Philosophy: Typing helps programmers avoid silly/careless mistakes * Problem: Given a vector of strings, find the alphabetically first string in the vector /** * Procedure: smallestString * Parameters: foo, a vector of strings * Purpose: Given a vector of strings, find the alphabetically first string in the vector * Produces: bar, a string * Preconditions: foo is nonempty. * Postconditions: bar.compareTo(vec.get(i)) <= 0 for all reasonable i */ public String smallestString(Vector foo) { // Grab the first string in the vector. String bar = (String) foo.get(0); for (int i = 1; i < foo.size(); i++) { if (bar.compareTo((String) vec.get(i)) <= 0) { // Do nothing } else { bar = (String) vec.get(i); } } // for return bar; } // smallestString(Vector) * Note: * We needed to cast foo.get(0) (and other stuff) * A type error is caught at run time, rather than compile time * Java 1.5 helps fix this kind of issue * Provide a mechanism to build generic homogeneous types * With the built-in collection types, add "type parameter" surrounded by angle brackets when declaring or using public String smallestString(Vector foo) { // Grab the first string in the vector. String bar = foo.get(0); for (int i = 1; i < foo.size(); i++) { if (bar.compareTo(vec.get(i)) <= 0) { // Do nothing } else { bar = vec.get(i); } } // for return bar; } // smallestString(Vector) * At compile time, Java ensures that you get the correct type of parameter. * Programmers can also type-parameterize their own interfaces, classes, and methods public interface Name { } // interface Name public class Name { } // interface Name * You can refer to T within the body Examples public interface Stack { public T pop(); public void push(T val); } // Stack public class Node { T val; Node next; ... public Node(T val) { this.val = val; this.next = null; } // Node(T) } Node foo = new Node("Hello"); // OK Node bar = new Node(BigInteger.ONE); // Fails Node bar = new Node(BigInteger.ONE); // Fails What if we want to restrict the type parameters (e.g., to being a number)? public class Node ... public class ComparableNode> extends Node { public int compareTo(ComparableNode other) { return this.val.compareTo(other.val); } } public T smallest(Vector foo) { // Grab the first string in the vector. T bar = foo.get(0); for (int i = 1; i < foo.size(); i++) { if (bar.compareTo(vec.get(i)) <= 0) { // Do nothing } else { bar = vec.get(i); } } // for return bar; } // smallest(Vector) Some issues: Suppose B is a subclass of A A a = ...; B b = ...; Vector va = ...; Vector vb = ...; Which of the following should be permitted? a = b; // OK b = a; // NO, can't assign member of superclass to subclass // Because a may not contain all the methods or fields // that the subclass expects va.add(a); // OK, seems to be the whole point va.add(b); // OK, subclasses can be used in place of superclasses vb.add(b); // OK, same reason as va.add(a) vb.add(a); // NO, when we get something from vb, we'll assume it // has all the B methods, and a may not. va = vb; // OK: 5 seems like Vector is a subsomething of Vector // (or at least than we can coerce each element) // NO: 2 Feels wrong; What happens to future type checking? vb = new Vector(); va = vb; va.add(new A()); B b = vb.get(); Conclusion: Java does not extend subtyping to parameterized classes * Related issue: Java does not permit arrays whose type is a type parameter public class List { T[] elements; // NO ... } Suppose Vector is a subclass of List Vector va = ...; List la = ...; la = va; // YES, SAFE va = la; // NO In old Java Vector va = ...; List la = ...; la = va; // YES /Behind the Scenes/ * No changes to Java VM! * The casting gets done by the compiler, rather than the programmer. * Plus additional type checking at compile time.