Java继承中的多态

Java中有两种形式可以实现多态:继承和接口,本文关注继承。

继承中多态只是实例方法的多态,属性和静态方法不适用多态。或者说实例方法是动态绑定的,静态方法和成员变量是静态绑定的。

1.实例方法

class Base{
   void method(){
       System.out.println("Base method!");
    }
}

class Sub extends Base{
    void method(){
        System.out.println("Sub method!");
        System.out.println(var);
    }
}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();
        who.method();
    }
}

结果

Sub method!

Java中只有private、static和final修饰的方法以及构造方法是静态绑定。

a、private方法的特点是不能被继承,也就是不存在调用其子类的对象,只能调用对象自身,因此private方法和定义该方法的类绑定在一起。
 
b、static方法又称类方法,类方法属于类文件。它不依赖对象而存在,在调用的时候就已经知道是哪个类的,所以是类方法是属于静态绑定。
 
c、final方法:final方法可以被继承,但是不能被重写,所以也就是说final方法是属于静态绑定的,因为调用的方法是一样的。
 总结:如果一个方法不可被继承或者继承后不可被覆盖,那么这个方法就采用的静态绑定。

2.成员变量

class Base{
    String var = "Base var";
}

class Sub extends Base{
    String var = "Sub var";
}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();
        System.out.println(who.var);
    }
}

结果

Base var

3.实例方法的多态是个例外。对于一个引用类型的变量,Java编译器按照它的声明的类型来处理,一个父类类型的变量引用了子类实例,该变量不会主动转为子类。

声明的类型并非实际的类型

class Base{

}

class Sub extends Base{

    String subVar = "Sub var";
    void subMethod(){
        System.out.println("Sub submethod!");
    }

}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();

        who.subMethod(); X
        who.subVar; X

    }

who是Base类型,根本就没有subMethod()方法和subVar属性,直接报错。

因此,最开始提到的1.实例方法(成员方法)的多态,其前提条件就是,子类的这个方法在父类中也有,即父类方法被重写了。

因此,在 被调用方法在父类中声明,也就是说被子类覆盖的方法 的前提之下,父类变量指向子类的引用,优先调用子类(实际类型)的方法,子类找不到在父类中找。这也是多态实现的另一种说法或原因。

class Base{
    void method(){
       System.out.println("Base method!");
    }
}

class Sub extends Base{

}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();
        who.method();

    }

当虚拟机创建子类的时候,会创建该子类的方法列表,同时包含父类的方法列表。同时虚拟机会参数引用的实际地址,找到创建的这个子类对象,查询方法列表,如果在子类对象中找到这个方法,就直接调用。

如果没找到,就去查询父类方法,调用父类的方法。

子类继承了父类,获得了父类的属性和方法?应是,子类中有父类对象(子类的初始化会引发父类的初始化,当然这须在父类未被初始会之时),子类中super()可以构造父类,子类可以调用父类中的方法,即对方法有使用权,并非真实拥有,即所有权。

 

原文地址:https://www.cnblogs.com/aidata/p/13659040.html