java编程思想---第八章(多态)
多态, 抽象, 继承, 这三种基本类型特征。
多态通过分离做什么,怎么做, 就是 讲接口和接口的具体实现分离开来。
1、8.1 向上转型的由来
先看下代码演化:
class Instrument { public void play(Note n) { System.out.println("Instrument.play()"); } }
public class Wind extends Instrument { // Redefine interface method:子类重写了父类play的方法,后期调用都是子类的实现,除非调用super来调用父类的paly 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);//Instrument 里传递的参数是它的子类(wind), } public static void main(String[] args) { Wind flute = new Wind();//构造空对象。 tune(flute); // Upcasting } }
class Brass extends Instrument { public void play(Note n) { System.out.println("Brass.play() " + n); } }
8.2.1 方法调用绑定
前期绑定:将一个方法调用同一个方法主体关联起来被称作绑定,若在程序执行之前进行绑定。
后期绑定:在运行期间 根据对象的类型进行绑定。亦可以称为动态绑定或运行时候绑定。
如果一种语言实现后期绑定,就必须具有某种机制,一遍在运行时候判断对象的类型,也就是说,编译器一直不知道对象的类型,但是方法调用机制能找到正确的方法体,加以调用。
java代码中除了static和final (private方法属于final方法) 之外,其他所有的方法都是后期绑定。
public class PrivateOverride { private void f() { System.out.println("private f()"); } public static void main(String[] args) { PrivateOverride po = new Derived(); po.f(); } } class Derived extends PrivateOverride { public void f() { System.out.println("public f()"); } }
实际结果调用的是父类的f()方法,也就是说 父类的private是不能覆盖的,
8.2.5域和静态方法
class StaticSuper { public static String staticGet() { return "Base staticGet()"; } public String dynamicGet() { return "Base dynamicGet()"; } } class StaticSub extends StaticSuper { public static String staticGet() { return "Derived staticGet()"; } public String dynamicGet() { return "Derived dynamicGet()"; } } public class StaticPolymorphism { public static void main(String[] args) { StaticSuper sup = new StaticSub(); // Upcast System.out.println(sup.staticGet());//调用父类的静态方法, System.out.println(sup.dynamicGet());//因为子类重写了父类方法,所以调用的是子类的方法 } }
静态方法是与类,而非与单个单向相关联。
8.3 构造器和多态
class Meal { Meal() { System.out.println("Meal()"); } } class Bread { Bread() { System.out.println("Bread()"); } } class Cheese { Cheese() { System.out.println("Cheese()"); } } class Lettuce { Lettuce() { System.out.println("Lettuce()"); } } class Lunch extends Meal { Lunch() { System.out.println("Lunch()"); } } class PortableLunch extends Lunch { PortableLunch() { System.out.println("PortableLunch()");} } public class Sandwich extends PortableLunch { private Bread b = new Bread(); private Cheese c = new Cheese(); private Lettuce l = new Lettuce(); public Sandwich() { System.out.println("Sandwich()"); } public static void main(String[] args) { new Sandwich(); } }
解析:1)优先调用父类构造器,不断的反复下去,一直到构造这种层次的根,也就是最底层的类,然后在调用子类。
2)按照声明顺序调用成员的初始化方法。
3)最后调用当前类的构造器主体。
这样达到所有的成员对象都被初始化。
8.3.2继承和初始化
若对象需要清理的时候,则,子类必须要重写父类方法,且在重写的方法重调用父类的dispose方法(super调用),否则父类清理不会发生。销魂的顺序和创建的顺序想法,优先销毁子类的方法,从里向外扩展。成员变量也是倒推销毁。
8.3.3构造器内部的多态方法的行为
class Glyph { void draw() { System.out.println("Glyph.draw()"); } Glyph() { System.out.println("Glyph() before draw()"); draw();//① 因为子类重写了darw ,所以调用子类方法 System.out.println("Glyph() after draw()"); } } class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r;//③ System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius);//②子类的初始值还未加载,所以第一次radius当前为0, } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5);//优先加载父类构造器 } }
初始化实际过程:
1)在其他事物发生之前,将分配给对象的存储空间初始化城二进制的零
2)优先调用父类构造器,到根部,
3)按照声明的顺序调用成员的初始化方法。
4)调用导出类的构造器主体
8.5用继承进行设计
class Actor { public void act() {} } class HappyActor extends Actor { public void act() { System.out.println("HappyActor"); } } class SadActor extends Actor { public void act() { System.out.println("SadActor"); } } class Stage { private Actor actor = new HappyActor(); public void change() { actor = new SadActor(); } public void performPlay() { actor.act(); } } public class Transmogrify { public static void main(String[] args) { Stage stage = new Stage(); stage.performPlay(); stage.change(); stage.performPlay(); } }
第一调用performplay 为happactor的对象,第二次给改变了,就为sadactor对象了,
对象引用在运行的时候可以与另一个不同的对象重新绑定起来,
8.5.2向下转型和运行时类别判定
class Useful { public void f() { System.out.println("userful f"); } public void g() { System.out.println("userful g");} } class MoreUseful extends Useful { public void f() { System.out.println( "mode f"); } public void g() { System.out.println( "mode g");} public void u() {} public void v() {} public void w() {} } public class RTTI { public static void main(String[] args) { Useful[] x = { new Useful(), new MoreUseful() }; x[0].f(); x[1].g(); // Compile time: method not found in Useful: //! x[1].u(); ((MoreUseful)x[1]).u(); // Downcast/RTTI ((MoreUseful)x[0]).u(); // Exception thrown 报错 } }
分类在转为子类的时候,会发生异常