class Stack<T> { ... } class Map<K, V> { ... }
Stack<Blob> blobStack = new Stack<Blob>()
Stack
” with no type variables is a valid class name.
import utils.Stack;
Class Stack<T> private T top = null private ArrayList<T> elts = new ArrayList<T>() void push(T t) { ... } T pop() { ... }
class Mailbox<T> private T slot void put(T t) { slot = t } T get() { return t } Mailbox<Letter> mailBox = new Mailbox<Letter>() mailBox.put(new Letter()) Letter letter = mailBox.get()
Step 1: erase type-variable declarations
class Mailbox<T> private T slot void put(T t) { slot = t } T get() { return t } Mailbox<Letter> mailBox = new Mailbox<Letter>() mailBox.put(new Letter()) Letter letter = mailBox.get()
Step 2: Replace type variables with their most general (most ancestral) type.
class Mailbox private T Object slot void put(T Object t) { slot = t } T Object get() { return t } Mailbox mailBox = new Mailbox() mailBox.put(new Letter()) Letter letter = mailBox.get()
Step 3: Cast to maintain type correctness.
class Mailbox private Object slot void put(Object t) { slot = t } Object get() { return t } Mailbox mailBox = new Mailbox() mailBox.put(new Letter()) Letter letter = (Letter) mailBox.get()
Ta da! No generics.
new
new
.
$ cat MailBox.java class MailBox<T> { private T mailBox = new T(); } $ javac -Xlint MailBox.java MailBox.java:2: unexpected type found : type parameter T required: class private T mailBox = new T(); ^ 1 error $
$ cat MailBox.java class MailBox<T> { /* blah blah blah */ } class test { private MailBox<int> mailBox = new MailBox<int>(); } $ javac -Xlint MailBox.java MailBox.java:6: unexpected type found : int required: reference private MailBox<int> mailBox = new MailBox<int>(); ^ MailBox.java:6: unexpected type found : int required: reference private MailBox<int> mailBox = new MailBox<int>(); ^ 2 errors $
static
$ cat MailBox.java import java.util.ArrayList; class MailBox<T> { static private T mailBoxs = new ArrayList<T>(); } $ javac -Xlint MailBox.java MailBox.java:4: non-static class T cannot be referenced from a static context static private T mailBoxs = new ArrayList<T>(); ^ MailBox.java:4: non-static class T cannot be referenced from a static context static private T mailBoxs = new ArrayList<T>(); ^ 2 errors $
public class MailBox<T extends Number> { public void copy(MailBox<T extends Integer> v) { // blah blah blah } // blah blah blah }
class Blob { ... } class Spot extends Blob { ... } Mailbox<Spot> spotBox = new Mailbox<Spot> Mailbox<Blob> blobBox = spotBox // ???
Mailbox
.
Mailbox<Spot> spotBox = new Mailbox<Spot> Mailbox<Blob> blobBox = spotBox // ???
So the assignment should be fine and dandy.
class Blob { ... } class Spot extends Blob { ... } Mailbox<Spot> spotBox = new Mailbox<Spot> Mailbox<Blob> blobBox = spotBox blobBox.put(new Blob) Spot spot = spotBox.get() // boom!
spotBox
as blobBox
can lead to run-time casting
exceptions, violating the generic guarantee.
any generic variant of class C type incompatible with every different generic variant of C.
void lock(Mailbox<Object> mb) { ... }
do it?
void lock(Mailbox<Object> mb) { ... }
only accepts mailboxes containing Object instances.
?
indicates that
void lock(Mailbox<?> mb) { ... }
does what we want, as long as lock()
doesn’t try to write polymorphic
references into mb
.
Object
instances.
void lock(Mailbox<?> mb) Object o = mb.get() // Ok
void lock(Mailbox<?> mb) mb.put(new Blob()) // Compile-time error mb.setOwner("Trollope") // Ok
void lock(Mailbox<Blob> mb) { ... }
doesn’t go far enough and this
void lock(Mailbox<?> mb) { ... }
goes too far.
extends
keyword:
void lock(Mailbox<? extends Blob> mb) {…}
void lock(Mailbox<? extends Blob> mb) Blob blob = mb.get() // Ok
class Mailbox<T extends Letter> { ... }
T
’s most general (ancestral) type is Letter
.
class Mailbox< T extends Letter & Refundable> { ... }
T
must satisfy (extend or implement) all bounds.
This page last modified on 22 September 2010. |