JavaSE之多态(一)

来源:互联网 发布:汽车资料查询软件 编辑:程序博客网 时间:2024/06/06 11:04

多态是java语言中的一个重要的基本特征,用来描述实物的多种状态。通过多态可以更好的消除类之间的耦合性。并且还可以提高代码的复用性。

(一)向上转型

对象既可以作为它本身的类型使用,也可以同过向上转型成为父类型使用。这种把子类的引用用于父类引用的做法叫作向上转型。

public class Demo1 {    public static void main(String[] args) {        Animal a1 = new Animal();        Animal.eat(a1);        Animal a2 = new Dog();        Animal.eat(a2);        Animal a3 = new Cat();        Animal.eat(a3);    }}class Animal{    public static void eat(Animal animal){        System.out.println(animal.getClass().getSimpleName()+"吃了一坨");    }}class Dog extends Animal{}class Cat extends Animal{} 

代码中a2和a3的形式就是向上转型的一种,分别将Dog和Cat向上转型成为其父类Animal。
向上转型是安全的,但是类型的转换必须在两个类具有继承(或实现)关系的前提下。

多态

为什么要向上转型?可以通过下面代码找到结论。

public class Demo1 {    public static void main(String[] args) {        Dog dog = new Dog();        dog.eat();        Cat cat = new Cat();        cat.eat();    }}class Animal{}class Dog extends Animal{    public void eat(){        System.out.println("dog eat!!");    }}class Cat extends Animal{    public void eat(){        System.out.println("Cat eat!!");    }}这个代码最终结果为   :dog eat!!Cat eat!!

也许会想说这样做挺好啊,老铁没毛病,但是这样做会出现一个问题,当有更多的动物被加入进来的时候我们为每一个动物子类都添加一个eat()方法。当我们在main中创建对象的时候也需要重新的new一个新的对象,并且调用其eat方法。这样做就是造成大量的重复代码。为了解决这种问题,就使用到了多态中的向上转型的这个特性。

public class Demo1 {    public static void main(String[] args) {        Animal.eat(new Dog());        Animal.eat(new Cat());        Animal.eat(new Donkey());    }}class Animal{    public static void eat(Animal animal){        System.out.println(animal.getClass().getSimpleName()+"eat!!");    }}class Dog extends Animal{}class Cat extends Animal{}class Donkey extends Animal{}控制台上的结果为:Dogeat!!Cateat!!Donkeyeat!!

通过这种方式将子类中的eat方法抽取出来,直接通过传入子类引用,将子类向上转型成Animal就可以完成前一段代码完成的结果,并且也不用重新写大量的重复代码。这样做的好处是提高了代码的重用性。这样写也能是代码更加的简洁优雅。

绑定

将一个方法调用同一个方法主体关联起来被称作绑定。

若在程序执行之前进行绑定叫做前期绑定(在此不再介绍因为我也不知道)。
显然,在程序运行时期根据对象类型进行绑定叫作后期绑定。
后期绑定也称为动态绑定或运行时绑定。

正是用过动态绑定这种机制,程序才可以在运行的时候清楚是谁的对象在调用方法(如dog.eat())。

这样我们就可以直接编写和父类打交道的程序代码了。

可扩展性

对于上面代码我们还可以看出,无论如何增加新的子类,原来类中的eat()方法依旧能照常使用,完全忽略它周围代码的变化,这正是我们期待多态所具有的特性。不会对程序中其他不受到影响的部分产生破坏,使代码具有可以更容易扩展的特性。

缺陷:覆盖私有方法

有时会出现这种情况

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()");    }}在控制台上得出的结果为: private f()

我们本想得出 public f() 的结论,却发现结果和想象的不同。

当我们在main方法中添加

Derived d = new Derived();        d.f();控制台上结果变为:private f()public f()

因为private方法被自动认为是final方法,并且对子类也是屏蔽的。这种情况下对于子类Derived,父类中的f()不可见。所以说此刻子类中的f()方法是它自身的方法,和父类无关。

这就提醒我们,在子类中,对于父类中的private方法,最好采用不同的名字来避免这种缺陷。
缺陷二

静态字段和静态方法不具有多态性。因为静态常常与类的对象相关联。

用继承进行设计

当学习了多态之后,会发现继承是之后就更加的便利了。所以思考是否要频繁的使用继承呢?但事实证明这样做会加剧设计的负担,会是程序的体系变得庞大复杂。

更好的方式是首先选择“组合”,特别是当我们在不能确定使用哪种方式的时候。因为组合不会强制程序的设计进入继承的层次机构中。

原创粉丝点击