Transcript chap08
8: Interfaces
• Interfaces
• “Multiple inheritance” in Java
– Name collisions when combining interfaces
• Extending an interface with inheritance
• Grouping constants
• Initializing fields in interfaces
• Exercises
Interfaces
• interface =a “pure” abstract class.
– All the methods are abstract ( with names, argument lists, and return
types, but without method bodies).
– methods implicitly public and abstract.
– Fields: implicitly static and final.
• To create an interface,
– use the interface keyword instead of the class keyword.
– Like a class, an interface can be defined as public (add the public
keyword before the interface keyword )
– or leave it off to “friendly”
• To make a class that conforms to a particular interface (or group
of interfaces) use the implements keyword.
• The interface is more than just an abstract class taken to the
extreme, since it allows you to perform a variation on C++’s
“multiple inheritance
Interfaces
import java.util.*;
interface Instrument {
// Compile-time constant:
int i = 5; // static & final
// Cannot have method definitions:
void play(); // Automatically public
String what();
void adjust();
}
class Wind implements Instrument {
public void play()
{ System.out.println("Wind.play()"); }
public String what()
{ return "Wind"; }
public void adjust() {}
}
class Percussion implements Instrument{
......
}
class Stringed implements Instrument { ......}
class Brass extends Wind {
public void play() { System.out.println("Brass.play()"); }
public void adjust() { System.out.println("Brass.adjust()"); }
}
class Woodwind extends Wind { ......}
public class Music5 { // Doesn't care about type, so new types
// added to the system still work right:
static void tune(Instrument i) { i.play(); }
static void tuneAll(Instrument[] e) {
for(int i = 0; i < e.length; i++) tune(e[i]);
}
public static void main(String[] args) {
Instrument[] orchestra = new Instrument[5];
int i = 0; // Upcasting during addition to the array:
orchestra[i++] = new Wind(); orchestra[i++] = new Percussion();
orchestra[i++] = new Stringed(); orchestra[i++] = new Brass();
orchestra[i++] = new Woodwind();
tuneAll(orchestra);
}
} ///:~
“Multiple inheritance” in Java
The interface isn’t simply a “more pure” form of abstract class.
It has a higher purpose than that.
Because an interface has no implementation at all—that is, there
is no storage associated with an interface, so the problems
seen in C++ do not occur with Java when combining multiple
interfaces.
import java.util.*;
interface CanFight {
void fight();
}
interface CanSwim {
void swim();
}
interface CanFly {
void fly();
}
class ActionCharacter {
public void fight() {}
}
class Hero extends ActionCharacter implements
CanFight, CanSwim, CanFly {
public void swim() {}
public void fly() {}
}
public class Adventure {
static void t(CanFight x) { x.fight(); }
static void u(CanSwim x) { x.swim(); }
static void v(CanFly x) { x.fly(); }
static void w(ActionCharacter x) { x.fight(); }
public static void main(String[] args) {
Hero h = new Hero();
t(h); // Treat it as a CanFight
u(h); // Treat it as a CanSwim
v(h); // Treat it as a CanFly
w(h); // Treat it as an ActionCharacter
// CanFight c=h;
// ActionCharacter a=h; CanFight c=a;
}
} ///:~
Extending an interface with inheritance
interface Monster { void menace(); }
interface DangerousMonster extends Monster { void destroy(); }
interface Lethal { void kill(); }
class DragonZilla implements DangerousMonster {
public void menace() {}
public void destroy() {}
}
interface Vampire extends DangerousMonster, Lethal {
void drinkBlood();
}
// how to implement Vampire?
public class HorrorShow {
static void u(Monster b) { b.menace(); }
static void v(DangerousMonster d) { d.menace(); d.destroy(); }
public static void main(String[] args) {
DragonZilla if2 = new DragonZilla();
u(if2); v(if2);
} } ///:~
Name collisions when combining interfaces
interface I1 { void f(); }
// Methods differ only by return type:
interface I2 { int f(int i); }
//! class C5 extends C implements I1 {}
interface I3 { int f(); }
//! interface I4 extends I1, I3 {}
class C {
///:~
public int f() { return 1; }
}
class C2 implements I1, I2 {
public void f() {}
public int f(int i) { return 1; } // overloaded
}
class C3 extends C implements I2 {
public int f(int i) { return 1; } // overloaded
}
class C4 extends C implements I3 { // Identical, no problem:
public int f() { return 1; }
}
Grouping constants
Because any fields in an interface are automatically static and
final, the interface is a convenient tool for creating groups
of constant values, as you would with an enum in C or C++.
For example:
package c08;
public interface Months {
int JANUARY = 1, FEBRUARY = 2, MARCH = 3,
APRIL = 4, MAY = 5, JUNE = 6,
JULY = 7, AUGUST = 8, SEPTEMBER = 9,
OCTOBER = 10, NOVEMBER = 11, DECEMBER = 12;
} ///:~
Now you can reference the values with expressions like
Months.JANUARY.
Of course, what you get is just an int, so there isn’t the extra type
safety that C++’s enum has.
But this (commonly used) technique is certainly an improvement
over hard-coding numbers into your programs. (That
approach is often referred to as using “magic numbers” and it
produces very difficult-to-maintain code.)
public final class Month2 {
private String name;
private int order;
private Month2(int ord, String nm) {
order = ord;
name = nm;
}
public String toString() { return name; }
public final static Month2
JAN = new Month2(1, "January"),
FEB = new Month2(2, "February"),
MAR = new Month2(3, "March"),
APR = new Month2(4, "April"),
MAY = new Month2(5, "May"),
JUN = new Month2(6, "June"),
JUL = new Month2(7, "July"),
AUG = new Month2(8, "August"),
SEP = new Month2(9, "September"),
OCT = new Month2(10, "October"),
NOV = new Month2(11, "November"),
DEC = new Month2(12, "December");
public final static Month2[] month = {
JAN, FEB, MAR, APR, MAY, JUN, JUL,
AUG, SEP, OCT, NOV, DEC };
public final static Month2 number(int ord) {
return month[ord - 1];
}
public static void main(String[] args) {
Month2 m = Month2.JAN;
System.out.println(m);
m = Month2.number(12);
System.out.println(m);
System.out.println(m == Month2.DEC);
System.out.println(m.equals(Month2.DEC))
;
}
}
System.out.println
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
print(boolean)
打印一个布尔值。
print(char)
打印一个字符。
print(char[])
打印一个字符数组。
print(double)
打印一个双精度浮点数。
print(float)
打印一个单精度浮点数。
print(int)
打印一个整型数。
print(long)
打印一个长整型数。
print(Object)
打印一个对象。
print(String)
打印一个串。
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
println()
结束行。
println(boolean)
打印一个布尔值后结束此行。
println(char)
打印一个字符后结束此行。
println(char[])
打印一个字符数组后结束此行。
println(double)
打印一个双精度浮点数后结束此行。
println(float)
打印一个单精度浮点数后结束此行。
println(int)
打印一个整数,结束此行。
println(long)
打印一个长整数,结束此行。
println(Object)
打印一个对象,结束此行。
println(String)
打印一个串,结束此行。
Initializing fields in interfaces
• Fields defined in interfaces are automatically static and
final. These cannot be “blank finals,” but they can be
initialized with nonconstant expressions. For example:
//: c08:RandVals.java // Initializing interface fields with
// non-constant initializers.
import java.util.*;
public interface RandVals {
Random rand = new Random();
int randomInt = rand.nextInt(10);
long randomLong = rand.nextLong() * 10;
float randomFloat = rand.nextLong() * 10;
double randomDouble = rand.nextDouble() * 10;
} ///:~
Exercises
5.
Create three interfaces, each owning two methods. Inherit a new interface from these
three interface, adding a new method. Create a class by implementing the new
interface and also inheriting from a concrete class. Now write four methods, each of
which takes one of the four interfaces as its argument(just like Page320
Adventure.java). In main( ), create an object of your class and pass it to each of the
methods.
class Base
interface A
+a()
+b()
interface B
+c()
+d()
interface D
+g()
class Sub
interface C
+e()
+f()
Inner classes
public class Parcel1 {
class Contents {
private int i = 11;
public int value() { return i; }
}
class Destination {
private String label;
Destination(String whereTo) { label = whereTo; }
String readLabel() { return label; }
}
// Using inner classes looks just like
// using any other class, within Parcel1:
public void ship(String dest) {
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args) {
Parcel1 p = new Parcel1(); p.ship("Tanzania");
}
} ///:~
RTTI
import java.util.*;
class Useful {
void p(String s) {System.out.println(s); }
public void f() { p("U.f");}
public void g() { p("U.g"); }
}
class MoreUseful extends Useful {
public void f() {p("M.f");}
public void g() {p("M.g");}
public void u() {p("M.u");}
public void v() {p("M.v");}
public void w() {p("M.w");}
}
public class RTTI {
public static void main(String[] args) {
Useful[] x = { new Useful(), new
MoreUseful() };
x[0].f();
x[1].g();
((MoreUseful)x[1]).u();
// Exception thrown
((MoreUseful)x[0]).u();
System.out.println("Terminate normally!");
}
} ///:~
RTTI
import java.util.*;
class Useful {
void p(String s) {System.out.println(s); }
public void f() { p("U.f");}
public void g() { p("U.g"); }
}
class MoreUseful extends Useful {
public void f() {p("M.f");}
public void g() {p("M.g");}
public void u() {p("M.u");}
public void v() {p("M.v");}
public void w() {p("M.w");}
}
public class RTTI {
public static void main(String[] args) {
Useful[] x = { new Useful(), new
MoreUseful() };
x[0].f();
x[1].g();
if ( x[1] instanceof MoreUseful )
((MoreUseful)x[1]).u();
if ( x[0] instanceof MoreUseful )
((MoreUseful)x[0]).u();
System.out.println("Terminate normally!");
}
} ///:~