|
|
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() { ... }
newnew.
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] }
staticclass 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()
newT 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.
