Polymorphism
多态
Upcasting revisited
示例:
public enum Note {
MIDDLE_C, C_SHARP, B_FLAT;
}
class Instrument {
public void play(Note n){
System.out.println("Instrument.play()");
}
}
public class Wind extends Instrument {
public void play(Note n){
System.out.println("Wind.play() "+n);
}
}
public class Music {
public static void tune(Instrument i){
i.play(Note.MIDDLE_C);
}
public static void main(String[] args) {
Wind flute = new Wind();
tune(flute);
}
}
输出:
Wind.play() MIDDLE_C
tune方法形参为Instrument,在main方法中传递了一个Wind参数,不需要强转。只要是继承于Instrument的类的实例,都可这样传递。
Forgetting the object type
你需要为父类的不同子类各写一个新的方法,以接收不同的参数。
示例:
public class Stringed extends Instrument {
public void play(Note n){
System.out.println("Stringed.play() " + n);
}
}
public class Brass extends Instrument {
public void play(Note n){
System.out.println("Brass.play() " + n);
}
}
public class Music2 {
public static void tune(Wind i){
i.play(Note.MIDDLE_C);
}
public static void tune(Stringed i){
i.play(Note.MIDDLE_C);
}
public static void tune(Brass i){
i.play(Note.MIDDLE_C);
}
public static void main(String[] args) {
Wind flute = new Wind();
Stringed violin = new Stringed();
Brass frenchHorn = new Brass();
tune(flute);
tune(violin);
tune(frenchHorn);
}
}
输出:
Wind.play() MIDDLE_C
Stringed.play() MIDDLE_C
Brass.play() MIDDLE_C
The twist
Method-call binding
Connecting a method call to a method body is called binding.
...The solution is called late binding,which means that the binding occurs at run time,based on the type of object.Late binding is also called dynamic binding or runtime binding.
...All method binding in Java uses late binding unless the method is static or final(private methods are implicitly final).
Produing the right behavior
一个经典的多态实例:
public class Shape {
public void draw(){}
public void erase(){}
}
public class Circle extends Shape {
public void draw(){
System.out.println("Circle.draw()");
}
public void erase(){
System.out.println("Circle.erase()");
}
}
public class Square extends Shape {
public void draw(){
System.out.println("Square.draw()");
}
public void erase(){
System.out.println("Square.erase()");
}
}
public class Triangle extends Shape {
public void draw(){
System.out.println("Triangle.draw()");
}
public void erase(){
System.out.println("Triangle.erase()");
}
}
public class RandomShapeGenerator {
private Random rand = new Random(47);
public Shape next(){
switch(rand.nextInt(3)){
default:
case 0: return new Circle();
case 1: return new Square();
case 2: return new Triangle();
}
}
}
public class Shapes {
private static RandomShapeGenerator gen = new RandomShapeGenerator();
public static void main(String[] args) {
Shape[] s = new Shape[9];
for(int i = 0; i < s.length; i++)
s[i] = gen.next();
for(Shape shp : s)
shp.draw();
}
}
输出:
Triangle.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Square.draw()
Triangle.draw()
Circle.draw()
上例子类声明均为父类型Shape
Extensibility
...In a well-designed OOP program,most or all of your methods will follow the model of tune() and communicate only with the base-class interface.Such a program is extensible because you can add new functionality by inheriting new data types from the common base class.
表示多态扩展性高的一个实例:
public class Instrument {
void play(Note n){
System.out.println("Instrument.play() "+n);
}
String what(){return "Instrument";}
void adjust(){
System.out.println("Adjusting Instrument");
}
}
public class Wind extends Instrument {
void play(Note n){
System.out.println("Wind.play() "+n);
}
String what(){return "Wind";}
void adjust(){
System.out.println("Adjusting Wind");
}
}
public class Percussion extends Instrument {
void play(Note n){
System.out.println("Percussion.play() "+n);
}
String what(){return "Percussion";}
void adjust(){
System.out.println("Adjusting Percussion");
}
}
public class Stringed extends Instrument {
void play(Note n){
System.out.println("Stringed.play() "+n);
}
String what(){return "Stringed";}
void adjust(){
System.out.println("Adjusting Stringed");
}
}
public class Brass extends Wind {
void play(Note n){
System.out.println("Brass.play() "+n);
}
void adjust(){
System.out.println("Adjusting Brass");
}
}
public class Woodwind extends Wind {
void play(Note n){
System.out.println("Woodwind.play() "+n);
}
String what(){return "Woodwind";}
}
public class Music3 {
public static void tune(Instrument i){
i.play(Note.MIDDLE_C);
}
public static void tuneAll(Instrument[] e){
for(Instrument i : e)
tune(i);
}
public static void main(String[] args) {
Instrument[] orchestra = {
new Wind(),
new Percussion(),
new Stringed(),
new Brass(),
new Woodwind()
};
tuneAll(orchestra);
}
}
输出:
Wind.play() MIDDLE_C
Percussion.play() MIDDLE_C
Stringed.play() MIDDLE_C
Brass.play() MIDDLE_C
Woodwind.play() MIDDLE_C
比较Music3与Music2的不同之处:Music2 main方法中,乐器声明为各自的类型,Music3 main方法中,乐器声明均为基类Instrument类型(用了一个数组),所以可以使用统一的形参类型:Instrument,而可以自动识别调用各子类中的方法.
...polymorphism is an important technique for the programmer to "separate the things that change from the things that stay the same."