Java三大特性之多态

引用多态的一个好例子

class A {
    public String show(D obj){              //方法一
        return ("A and D");
    }
    public String show(A obj){              //方法二
        return ("A and A");
    }
}
class B extends A{
    public String show(B obj){              //方法三
        return ("B and B");
    }
    public String show(A obj){              //方法四
        return ("B and A");
    }
}
class C extends B{
}
class D extends
B{
}
public class Test1 {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        System.out.println("1--" + a1.show(b));
        System.out.println("2--" + a1.show(c));
        System.out.println("3--" + a1.show(d));
        System.out.println("4--" + a2.show(b));
        System.out.println("5--" + a2.show(c));
        System.out.println("6--" + a2.show(d));
        System.out.println("7--" + b.show(b));
        System.out.println("8--" + b.show(c));
        System.out.println("9--" + b.show(d));
    }
}

让我们分析一下,理清其中各个类的继承关系


A,B,C,D类之间的继承关系

那我们开始分析输出A a1 = new A();这是普通的创建对象,故a1拥有调用方法一和方法二的能力。那么究竟调用哪个方法呢,这里面涉及方法的重载。其实,在编译的时候,编译器已经进行了前期绑定,即把show();方法与类中的方法主体2进行绑定。就是说,在编译时,系统就已经知道应该调用哪个方法,即使你有方法的重载。

故 a1.show(b)会与方法二绑定;a1.show(c)会与方法二绑定;a1.show(d)会与方法一绑定。且都在编译时完成绑定

但A a2 = new B();就涉及了多态 了,B实现了向上转型。创建了一个父类引用,指向子类对象。这样的做法很常见,因为这样不仅增加了灵活性(父类引用可以随时指向任意子类对象),也提高了扩展性。但要知道的是,向上转型的缺点,就是不能调用子类中有而父类没有的方法。

故A a2 = new B();中,方法四对方法二进行了重写,所以a2拥有调用方法一和方法四的能力,而方法三不能调用(由上一段可知)。所以,在编译时, a2.show(b)会与方法四绑定; a2.show(c)会与方法四绑定; a2.show(d)会与方法一绑定

B b = new B();这是普通的创建子类对象,B继承于A,且方法四重写了方法二,所以b拥有调用方法一,方法三,方法四的能力。所以b.show(b)会与方法三绑定,b.show(c)会与方法三绑定,b.show(d)会与方法一绑定

所以,答案是
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D

深入理解多态

Java中,有三大特性——封装、继承和多态。那何为多态呢?以我之见,多态变现了事物的多种状态。比如,中国人可以说是亚洲人,也可以说是人,当然后者的范围比前者的要大。这里面涉及了继承关系,有继承也就才有多态。

假如,Asian类继承了Man类,那么普通人觉得Man m = new Asian();这里涉及了多态,为什么呢?因为这里是父类引用指向子类对象(也可以是接口指向实现类对象),有向上转型的特征。

多态的好处:

  • 减少代码的耦合
    (例如在接口的实现中,分离做什么和怎么做)
  • 提高代码的可维护性
    (随着子类的扩展,而不用修改其他代码,父类引用可指向任意子类对象)
  • 增强父类的功能
    (有子类的继承,父类的引用就可以引用子类重写的方法)
  • 。。。待学习的深入进行总结

方法的调用绑定

《Thinking in Java》中

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

其中又分为前期绑定和后期绑定(动态绑定)

前期绑定即编译器在编译的过程中,把方法调用和方法主体进行绑定的过程。由编译器判断调用哪个方法。如开头的例子,编译器根据是否由向上转型,进行了最佳匹配,把匹配到方法和引用绑定在一起,执行时直接调用

后期绑定即在程序运行的过程中,编译器一直不知道对象的类型,直到方法在调用时,根据传入的类型信息,才进行绑定相应的方法。这种方法需要注意的是,必须在运行时能指明相应的信息,从而调用不同的方法

继承与清理

在垃圾回收器的机制中,有自适应的回收技术,会判断对象是否是“活的”,怎么判断?判断该对象是否还有引用。如果没引用,就会被标记或者复制从而被清除。

一般来说,对象的清理按初始化顺序进行清理。在多重继承的类对象中,会在导出类被销毁后,才会销毁基类。但如果存在对象被共享的情况时,就要注意了,共享的对象肯定是在没引用时才会被清理。

尽可能避免在构造器中调用方法

在继承的类之间,往往会有方法的重写,那么,如果在父类构造器中,如果调用了父类被重写的方法,则会调用子类重写了的方法

推荐阅读更多精彩内容