Thinking In Java 4th Chap8 多态(未完)
多态的意义:改善代码的可读性并且使得程序“可扩展”
多态方法调用允许一种类型表现出与其他相似类型之间的"区别",基于方法的行为不同而表现出来
将一个方法调用同一个方法主体关联起来称作绑定,程序执行前绑定称为前期绑定,运行时根据对象的类型进行绑定称为后期绑定。
Java中除了static和final(包括private)方法,都采用后期绑定。
向上转型可以表现为此语句:(在调用方法时总是会进行正确的调用,也即调用正确的子类的方法)
(Shape类是Circle类的基类)Shape s = new Circle();
调用方法:s.draw();(draw()方法已经在Circle类中被覆写)实际上调用的还是Circle.draw(),虽然对象s被声明为Shape(但是指向Circle类的引用)
1 package Music; 2 enum Note{ 3 MIDDLE_C,C_SHARP,B_FLAT 4 } 5 class Instrument{ 6 void play(Note n) { 7 System.out.print("Instrument.play()" + n); 8 } 9 }; 10 class Percussion extends Instrument{ 11 void play(Note n) { 12 System.out.print("Percussion.play()" + n); 13 } 14 }; 15 class Stringed extends Instrument{ 16 void play(Note n) { 17 System.out.print("Stringed.play()" + n); 18 } 19 }; 20 class Wind extends Instrument{ 21 void play(Note n) { 22 System.out.print("Wind.play()" + n); 23 } 24 }; 25 class Music4{ 26 static void tune(Instrument i){ 27 i.play(Note.MIDDLE_C); 28 } 29 static void tuneAll(Instrument[] e){ 30 for(Instrument i:e){ 31 tune(i); 32 } 33 } 34 public static void main(String[]args){ 35 Instrument[]orchestra={ 36 new Wind(), 37 new Percussion(), 38 new Stringed(), 39 }; 40 tuneAll(orchestra); 41 } 42 };
上述“向上引用”的缺陷是:如果覆写了private方法,那么“向上引用”的结果是调用基类的private方法
只有普通的方法的调用可以是多态的,如果直接访问某个域,那么访问就在编译期解析:
1 class Super{ 2 public int field=0; 3 public int getField(){ 4 return field; 5 } 6 } 7 class Sub extends Super{ 8 public int field=1; 9 public int getField(){ 10 return field; 11 } 12 public int getSuperField(){ 13 return super.field; 14 } 15 } 16 class FieldAccess{ 17 public static void main(String []args){ 18 Super sup=new Sub();//upcasting 19 System.out.println("sup.field="+sup.field+",sup.getfield()="+sup.getField()); 20 Sub sub=new Sub(); 21 System.out.println("sub.field="+sub.field+",sub.getfield()="+sub.getField()+",sub.getSuperField()="+sub.getSuperField()); 22 23 } 24 }/**output: 25 sup.field=0,sup.getfield()=1 26 sub.field=1,sub.getfield()=1,sub.getSuperField()=0*/
如果某个方法是静态的,则不具备多态性:
1 class StaticSuper{ 2 public static String staticGet(){ 3 return "Base staticGet()"; 4 } 5 public String dynamicGet(){ 6 return "Base dynamicGet()"; 7 } 8 } 9 class StaticSub extends StaticSuper{ 10 public static String staticGet(){ 11 return "Sub staticGet()"; 12 } 13 public String dynamicGet(){ 14 return "Sub dynamicGet()"; 15 } 16 } 17 class StaticPolymorphism{ 18 public static void main(String[]args){ 19 StaticSuper sup=new StaticSub(); 20 System.out.println("sup.staticGet()="+sup.staticGet()); 21 System.out.println("sup.dynamicGet()="+sup.dynamicGet()); 22 } 23 } 24 /**output: 25 * sup.staticGet()=Base staticGet() 26 * sup.dynamicGet()=Sub dynamicGet()*/
构造器和多态(构造器隐式的声明为static)
构造器的调用顺序实例:
1 class Meal{ 2 Meal(){ 3 System.out.print("Meal()"); 4 } 5 } 6 class Bread{ 7 Bread(){ 8 System.out.print("Bread()"); 9 } 10 } 11 class Cheese{ 12 Cheese(){ 13 System.out.print("Cheese()"); 14 } 15 } 16 class Lettuce{ 17 Lettuce(){ 18 System.out.print("Lettuce()"); 19 } 20 } 21 class Lunch extends Meal{ 22 Lunch(){ 23 System.out.print("Lunch()"); 24 } 25 } 26 class PortableLunch extends Lunch{ 27 PortableLunch(){ 28 System.out.print("PortableLunch()"); 29 } 30 } 31 class Sandwich extends PortableLunch{ 32 private Bread b = new Bread(); 33 private Cheese c= new Cheese(); 34 private Lettuce l = new Lettuce(); 35 Sandwich(){ 36 System.out.print("Sandwich()"); 37 } 38 public static void main(String[]args){ 39 new Sandwich(); 40 } 41 } 42 /**output: 43 * Meal()Lunch()PortableLunch()Bread()Cheese()Lettuce()Sandwich()*/
可见构造器的调用顺序:基类构造器->组合方法调用成员构造器->继承类构造器(自己)
继承和清理: