面向对象编程——多态

       Java引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型有声明该变量时使用的类型决定,运行时类型由实际赋给改变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

package polymorphism;

class Base {

    public int book=6;
    public void baseinfo(){
        System.out.println("父类的普通方法!");
    }

    public void test(){
        System.out.println("父类的被覆盖的方法");
    }

}
public class Sub extends Base{

    public String book="Java开发";
    public void test(){
        System.out.println("子类的覆盖父类的方法");
    }

    public void subinfo(){
        System.out.println("子类的普通方法");
    }
    public static void main(String[] args) {

        Base bc = new Base();
        System.out.println(bc.book);
        bc.baseinfo();
        bc.test();

        System.out.println("--------------------");

        Sub sc = new Sub();
        System.out.println(sc.book);
        sc.baseinfo();
        sc.test();
        sc.subinfo();

        System.out.println("--------------------");

        Base bs = new Sub();
        System.out.println(bs.book);
        bs.baseinfo();
        bs.test();

        //因为bs的编译时类型是Base
        //Base类没有提供subinfo()方法,所以下面代码编译时会出现错误
        //bs.subinfo();
    }

}
运行结果:

6
父类的普通方法!
父类的被覆盖的方法
--------------------
Java开发
父类的普通方法!
子类的覆盖父类的方法
子类的普通方法
--------------------
6
父类的普通方法!
子类的覆盖父类的方法

       上面程序的main()显式创建了三个引用变量,对于前两个引用变量bc和sc,它们编译时类型和运行时类型完全相同,因此调用他们的成员变量和方法非常正常,完全没有任何问题。但第三个引用变量bs则比较特殊,它的编译时类型是Base,而运行时类型是Sub,当调用该变量的test()方法(Base类中定义了该方法,子类Sub覆盖了父类的该方法)时,实际执行的是Sub类中的覆盖后的test()方法,这就可能出现多态了。

       因为子类其实是一种特殊的父类,因此Java允许把一个子类对象直接赋给一个父类引用变量,无需任何类型转换,或者被称为向上转型(upcasting),向上转型由系统自动完成。

       当把一个子类对象直接赋给父类引用变量时,例如上面的 Base bs = new Sub(); 这个bs引用变量的编译时类型是Base,而运行时是Sub,当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就可能出现:相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态。

       上面的main()方法注释了bs.subinfo();这行代码会在编译时发生错误。虽然bs引用变量实际上包含subinfo()方法(例如,可以通过反射来执行该方法),但因为它的编译时类型为Base,因此编译是无法调用subinfo()方法。

       与方法不同的是,对象的实例变量则不具备多态性,比如上面的bs引用变量,程序中输出它的book实例变量时,并不是输出Sub类里定义的实例变量,而是输出Base类的实例变量。

       注意:
       引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的的方法。因此,编写Java代码时,引用变量只能调用声明该变量时所用类里包含的方法。例如,通过Object p=new Person()定义了一个变量p,则这个p只能调用Object类的方法(子类重写父类方法时,调用子类重写后的方法),而不能调用Person类里定义的方法。
通过引用变量来访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它运行时类型所定义的成员变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值