多态的理解
多态很常识的理解就是向上转型,但是只记住这个概念会出错的,比如看下面的代码
// polymorphism/PrivateOverride.java // Trying to override a private method // {java polymorphism.PrivateOverride} package polymorphism; public class PrivateOverride { private void f() { System.out.println("private f()"); } public static void main(String[] args) { PrivateOverride po = new Derived(); po.f(); } } public Derived extends PrivateOverride { public void f() { System.out.println("public f()"); } }
private f()
这里的private默认是final的,但是为什么你还能“重写”?因为你根本不是重写,你是在派生类扩展了一个方法,所以向上转型后只会调用基类的方法。
针对这种情况,我们比较推荐加上@Ovrride注解,因为这样可以在编译的时候就报错让我们发现。
error: method does not override or
implement a method from a supertype
多态还有一个陷阱就是属性与静态方法
package Test; // polymorphism/FieldAccess.java // Direct field access is determined at compile time class Super { public int field = 0; public int getField() { return field; } } class Sub extends Super { public int field = 1; @Override public int getField() { return field; } public int getSuperField() { return super.field; } } public class FieldAccess { public static void main(String[] args) { Super sup = new Sub(); // Upcast System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField()); Sub sub = new Sub(); System.out.println("sub.field = " + sub.field + ", sub.getField() = " + sub.getField() + ", sub.getSuperField() = " + sub.getSuperField()); } }
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1, sub.getSuperField() = 0
当 Sub 对象向上转型为 Super 引用时,任何属性访问都被编译器解析,因此不是多态的。在这个例子中,Super.field 和 Sub.field 被分配了不同的存储空间,因此,Sub 实际上包含了两个称为 field 的属性:它自己的和来自 Super 的。然而,在引用 Sub 的 field 时,默认的 field 属性并不是 Super 版本的 field 属性。为了获取 Super 的 field 属性,需要显式地指明 super.field。
// polymorphism/StaticPolymorphism.java // static methods are not polymorphic 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()"; } @Override public String dynamicGet() { return "Derived dynamicGet()"; } } public class StaticPolymorphism { public static void main(String[] args) { StaticSuper sup = new StaticSub(); // Upcast System.out.println(StaticSuper.staticGet()); System.out.println(sup.dynamicGet()); } } Base staticGet() Derived dynamicGet()
静态它只与类相关,多态和它没关系。
构造器具有多态性吗? 答案是否定的,构造器如何具备多态性啊,这个要从对象上理解。虽然宝马和奥迪都是车,但是车的配件不一样啊,构造器的作用就是将制造这些配件也就是初始化变量。
继承和清理
// polymorphism/Frog.java // Cleanup and inheritance // {java polymorphism.Frog} package polymorphism; class Characteristic { private String s; Characteristic(String s) { this.s = s; System.out.println("Creating Characteristic " + s); } protected void dispose() { System.out.println("disposing Characteristic " + s); } } class Description { private String s; Description(String s) { this.s = s; System.out.println("Creating Description " + s); } protected void dispose() { System.out.println("disposing Description " + s); } } class LivingCreature { private Characteristic p = new Characteristic("is alive"); private Description t = new Description("Basic Living Creature"); LivingCreature() { System.out.println("LivingCreature()"); } protected void dispose() { System.out.println("LivingCreature dispose"); t.dispose(); p.dispose(); } } class Animal extends LivingCreature { private Characteristic p = new Characteristic("has heart"); private Description t = new Description("Animal not Vegetable"); Animal() { System.out.println("Animal()"); } @Override protected void dispose() { System.out.println("Animal dispose"); t.dispose(); p.dispose(); super.dispose(); } } class Amphibian extends Animal { private Characteristic p = new Characteristic("can live in water"); private Description t = new Description("Both water and land"); Amphibian() { System.out.println("Amphibian()"); } @Override protected void dispose() { System.out.println("Amphibian dispose"); t.dispose(); p.dispose(); super.dispose(); } } public class Frog extends Amphibian { private Characteristic p = new Characteristic("Croaks"); private Description t = new Description("Eats Bugs"); public Frog() { System.out.println("Frog()"); } @Override protected void dispose() { System.out.println("Frog dispose"); t.dispose(); p.dispose(); super.dispose(); } public static void main(String[] args) { Frog frog = new Frog(); System.out.println("Bye!"); frog.dispose(); } }
Creating Characteristic is alive Creating Description Basic Living Creature LivingCreature() Creating Characteristiv has heart Creating Description Animal not Vegetable Animal() Creating Characteristic can live in water Creating Description Both water and land Amphibian() Creating Characteristic Croaks Creating Description Eats Bugs Frog() Bye! Frog dispose disposing Description Eats Bugs disposing Characteristic Croaks Amphibian dispose disposing Description Both wanter and land disposing Characteristic can live in water Animal dispose disposing Description Animal not Vegetable disposing Characteristic has heart LivingCreature dispose disposing Description Basic Living Creature disposing Characteristic is alive
初始化的时候从上到下,清理的时候从下到上,一定要手动super调用基类的dispose()
构造器内部的多态行为
// polymorphism/PolyConstructors.java // Constructors and polymorphism // don't produce what you might expect class Glyph { void draw() { System.out.println("Glyph.draw()"); } Glyph() { System.out.println("Glyph() before draw()"); draw(); 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); } @Override void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); } } public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); } }
Glyph() before draw() RoundGlyph.draw(), radius = 0 Glyph() after draw() RoundGlyph.RoundGlyph(), radius = 5
- 在所有事发生前,分配给对象的存储空间会被初始化为二进制 0。
- 如前所述调用基类构造器。此时调用重写后的
draw()
方法(是的,在调用 RoundGraph 构造器之前调用),由步骤 1 可知,radius 的值为 0。 - 按声明顺序初始化成员。
- 最终调用派生类的构造器。
因此,编写构造器有一条良好规范:做尽量少的事让对象进入良好状态。如果有可能的话,尽量不要调用类中的任何方法。在构造器中唯一能安全调用的只有基类的 final 方法(包括 private 方法,它们自动属于 final)。这些方法不能被重写,因此不会产生意想不到的结果。你可能无法永远遵循这条规范,但应该朝着它努力。
协变类型,怎么讲,容易误解,感觉没什么实际用处
// polymorphism/CovariantReturn.java class Grain { @Override public String toString() { return "Grain"; } } class Wheat extends Grain { @Override public String toString() { return "Wheat"; } } class Mill { Grain process() { return new Grain(); } } class WheatMill extends Mill { @Override Wheat process() { return new Wheat(); } } public class CovariantReturn { public static void main(String[] args) { Mill m = new Mill(); Grain g = m.process(); System.out.println(g); m = new WheatMill(); g = m.process(); System.out.println(g); } }
Grain
Wheat
这也是多态一种表现
利用多态和继承我们可以实现一种状态模式
// polymorphism/Transmogrify.java // Dynamically changing the behavior of an object // via composition (the "State" design pattern) class Actor { public void act() {} } class HappyActor extends Actor { @Override public void act() { System.out.println("HappyActor"); } } class SadActor extends Actor { @Override 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(); } }
HappyActor
SadActor
向下转型也是可以的,不过需要强转,并且很容易出错,基本不用。
// polymorphism/RTTI.java // Downcasting & Runtime type information (RTTI) // {ThrowsException} class Useful { public void f() {} public void g() {} } class MoreUseful extends Useful { @Override public void f() {} @Override public void 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 } }
编译和运行都会让你拒绝向下转型。