Java语言中的多态性

概述

  多态是面向对象的三大特征之一,另外两个是封装、继承。

  之前看过一个对多态很形象的解释:如果编译时类型和运行时类型不一样的话,就会出现多态。

 

 

编译时类型与运行时类型

  这里有编译时类型和运行时类型,这是因为Java有点特别,因为java代码都要编译成*.class文件(此阶段叫编译),然后*.class文件在JVM里面运行(此阶段叫运行)。所以,这两种类型的区别之处就在于:

  1、编译时类型就是在声明一个变量时,指定该变量的类型。

  2、而运行时类型,就是真正赋值给这个变量的值的类型。

  为了方便理解,下面举一个简单的例子:

double a = 10;

  上面这行代码中,声明了一个变量,变量的编译时类型是double类型,而赋值给a的值是int类型,所以a的运行时类型是int。这个例子只是为了方便理解,解释不一定正确。

 

 

对象中的多态

  直接看例子吧:

class BaseClass{
    public int age = 100;
    public void showInfo(){
        System.out.println("Base class showInfo");
    }
    public void say(){
        System.out.println("Base class say");
    }
}

class SubClass extends BaseClass{
    public int age = 200;
    public String  name = "demo";
    public void say(){
        System.out.println("Sub class say");
    }
    public void speak(){
        System.out.println("sub class speak");
    }
}

public class Test{
    public static void main(String[] args){

        BaseClass bc = new SubClass();
        // 注意,BaseClass是编译时类型,而SubClass是运行时类型

        bc.showInfo();
        // Base class showInfo

        bc.say();
        // Sub class say

        // 编译出错
        // bc.speak();

        System.out.println(bc.age);
        // 100

        // 编译出错
        // System.out.println(bc.name);
    }
}

  多态的原则(结论),有几个注意点:

  1、编译时类型必须是运行时类型的父类或者间接父类。编译时类型不能是运行时类型的子类。可以形象记忆:父类比子类范围大,将父类赋值给子类,会有精度损失,所以会出错。

  2、子类可以继承、覆盖父类的成员属性,或者增加自己的成员属性;同样子类也可以继承、重写父类的成员方法,或者增加自己的成员方法。

  3、创建的对象(编译时类型为父类类型,运行时类型为子类类型),通过该对象,只能访问或者调用编译类型的成员属性和成员方法(父类中定义的成员属性和成员方法),而不能访问子类中新增的成员属性和成员方法。这是在编译阶段需要注意的,如果通过该对象访问子类中的成员属性和成员方法,就会报错。

  4、前面已经说了,通过对象引用,只能访问或者调用两个类中共有的那些成员属性和方法。但是前面也,在子类中,子类是可以覆盖或者重写从父类中继承过来的成员属性和成员方法。

    I、对于成员属性来说:无论在子类中是否覆盖父类中的成员属性,在真正运行时,访问该成员属性,得到的值都是父类中那个成员属性值(即使子类重写之后赋了其他值)。

    II、对于成员方法来说:如果子类中没有重写父类中的方法,那么调用的就是父类中的成员方法;如果子类中重写了父类中的方法,那么运行时调用的就是子类中重写之后的成员方法。

  5、如果非要使用子类中新增的成员属性或者覆盖的成员属性,或者新增的成员方法,可以使用(type)variable来强制将编译类型为父类,运行类型为子类的对象转换为子类类型,之后就可以了。

 

class BaseClass{
    public int age = 100;
    public void showInfo(){
        System.out.println("Base class showInfo");
    }
    public void say(){
        System.out.println("Base class say");
    }
}

class SubClass extends BaseClass{
    public int age = 200;
    public String  name = "demo";
    public void say(){
        System.out.println("Sub class say");
    }
    public void speak(){
        System.out.println("sub class speak");
    }
}

public class Test{
    public static void main(String[] args){

        BaseClass bc = new SubClass();

        bc.showInfo();
        // Base class showInfo

        bc.say();
        // Sub class say

        // 编译错误
        // bc.speak();

        ((SubClass)bc).speak();
        // sub class speak

        System.out.println(bc.age);
        // 100

        // 编译错误
        // System.out.println(bc.name);

        System.out.println(((SubClass)bc).name);
        // demo
    }
}

  

posted @ 2018-10-27 11:56  寻觅beyond  阅读(956)  评论(0)    收藏  举报
返回顶部