|
![]() |
1+1
,1L+1L
,1.0f+1.0f
,1.0+1.0
CardDeck() { ... }
CardDeck(int seed) { ... }
class blob {...} class spot extends blob {...} blob b = new spot();
Object
.
class stack void push(Object o) { ... } Object pop() { ... }
Stack stk = new Stack() stk.push("hello") String str = (String) stk.pop()
stk.push(1) String str = (String) stk.pop()
Stack stk = new Stack() stk.push(new Spot()) Drip drip = (Drip) stk.pop() // boom!
class StringStack void push(String str) { ... } String pop() { ... } class DripStack void push(Drip drip) { ... } drip pop() { ... } // and so on.
T
is a type variable.
class TStack void push(T t) { ... } T pop() {...} TypeVariable T = String TStack stringStk = new TStack() stringStk.push("hello") String str = stringStk.pop() T = Drip TStack dripStk = new TStack() dripStk.push(new Drip()) Drip drip = dripStk.pop()
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() { ... }
new
new
.
class Stack<T> private final int max = 10 private T elements[] =new T[max]
class Stack<T> private final int max = 10 private Object stk[] = new Object[max] T pop() { return (T) stk[--top] }
static
class SharedMailbox<T> privatestatic Tslot = null publicstatic TpickUp() { return slot } public static deliver(T t) { slot = t }
Stack<int> intStack = new Stack<int>()
Stack<Integer> integerStack = new Stack<Integer>() integerStack.push(1) int i = integerStack.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
.
class MailBox<T> // Start with a default letter. private T mailBox =new T()
new
T
is replaced by Object
, which isn't useful.
class MailBox // Start with a default letter. private Object mailBox = new Object()
Stack<int> intStack = new Stack<int>()
Why not?
T
by it's most distant ancestor.
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.
Mailbox<Spot> spotBox = new Mailbox<Spot> Mailbox<Blob> blobBox = spotBox // Error Spot spots[] = new Spot [10] Blob blobs[] = spots // Ok
blobs[0] = new Blob() // Runtime error
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.