Overview
csc207-01-grader@grinnell.edu
not csc207.01-grader@grinnell.edu
. (No dots, just dashes.)csc207-01-grader@grinnell.edu
Key idea: If an A is a B, then we can use an A anywhere we expect a B.
In Java terms: If Class A implements interface B, an object of class A can be used wherever we expect a parameter or variable of interface B.
interface Shuffler {
void shuffle(Deck d);
}
class Student implements Shuffler {
void shuffle(Deck d) {
...
}
}
class Gravity implements Shuffler {
void shuffle(Deck d) {
..
}
}
B thing = new A();
public static void whatever(B param) { ... }
whatever(new A());
Why have interfaces?
Because the client code need not know which object is implementing the method,
Interfaces serve as a kind of prototype for a set of functions.
Can a class implement multiple interfaces, or only one?
A class can implement an arbitrarily large number of interfaces.
class Student implements Shuffler, TextBlock
needsshuffle
androw
andwidth
, andheight
.
Do interfaces get separate files?
Definitely.
TextBlock tb
means that tb
references some object that implements
the TextBlock
interface. (The Java compiler will do its best
to enforce that rule.)
dump(PrintWriter pen, TextBlock tb)
means that the procedure takes
as input a PrintWriter and any object that implements the TextBlock
interface.
What are static and dynamic binding?
In statically-typed language, the type is bound at compile time. In dynamically-typed languages, the type is bound at runtime.
We haven’t covered superclasses and inheritance yet, but some of you have been asking about the difference.
In Java,
Different contexts call for different choices.
A different model of polymorphism. We acheive multiple forms by adding type parameters to class definitions and method definitions.
public class NamedInteger {
String name;
Integer val;
static Integer numNamedInts; // A counter
public NamedInteger(String name, Integer val) {
this.name = name;
this.val = val;
++numNamedInts;
} // NamedInteger(String,Integer)
public String toString() {
return this.name + ": " + this.val;
} // toString()
}
If we want a NamedDouble
class, we could use copy/paste/change.
public class NamedDouble {
String name;
Double val;
static Integer numNamedInts;
public NamedDouble(String name, Double val) {
this.name = name;
this.val = val;
++numNamedInts;
} // NamedDouble(String,Double)
public String toString() {
return this.name + ": " + this.val;
} // toString()
}
Why is copy/paste/change a bad idea, even though it seems really fast?
Java provides generics as a way of dealing with this issue.
public class NamedThing<T> {
String name;
T val;
static Integer numNamed; // A counter
public NamedThing(String name, T val) {
this.name = name;
this.val = val;
++numNamedInts;
} // NamedThing(String,Thing)
public String toString() {
return this.name + ": " + this.val;
} // toString()
}
NamedThing<Integer> i = new NamedThing<Integer>("eye", 3);
NamedThing<Double> j = new NamedThing<Double>("dub", 3.3);
NamedThing<Double> k = new NamedThing<Double>("bud", 3.7);
NamedThing<Student> l = new NamedThing<Student>("sam", new Student(...));
We have multiple forms, where the type parameter lets us choose between forms.
Warning: There are a lot of subtleties with generics in Java. We’ll discuss them as they become important.
for (int i = 0; i < 10; i++) {
strings.set(i, "x" + i);
} // for