多态

若是父类中没有sing()方法,则报错

public class PolyTest
{
    public static void main(String[] args)
    {
        Parent p = new Child();
        p.sing();
        System.out.println(p.getClass());
    }
}

class Parent
{
    //注释掉sing()方法后报错,父类一定要有sing方法
    /*public void sing() 
    {
        System.out.println("Parent is singing");
    }*/
}

class Child extends Parent
{
    public void sing()
    {
        System.out.println("Child is singing");
    }

报错如下:

PolyTest.java:6: 错误: 找不到符号
                p.sing();
                 ^
  符号:   方法 sing()
  位置: 类型为Parent的变量 p
  1 个错误

原因分析:找不到符号,符号是方法是sing(),类型是Parent的变量,它会在Parent类里去找sing()方法,而Parent类里没有sing()方法这个符号,所以报错。怎么理解呢,这里p虽然是指向一个子类型的引用,但是p是父类型的,什么类型调用什么方法(即使强转类型,也是强转成什么类型就调用什么类里的方法),而Parent类型没有sing()方法,调用不到肯定会出错。
对于多态,要求p指向了一个子类并且调用子类对象某一个方法,这个方法你必须在父类中也要存在,因为这个引用p它本身是父类型的,它是什么类型的它才能去使用什么类型的方法,虽然它实际指向的是一个子类的对象,但是p本身还是一个父类型的一个引用,也就是它还是一个父类型的变量,你不可能说父类型里面没有,而子类型里有我就能去调用,调用不了的,它首先去检查父类型里面是否定义了sing()这样一个方法,如果有的话,它再去子类里面去调用子类的sing()方法(因为p毕竟指向的是子类实例),如果没有则直接调用父类的sing()方法


结合下面代码更容易理解多态。

public class PolyTest
{
    public static void main(String[] args)
    {
        Parent p = new Child();
        Child c = (Child)p;
        c.sing();//当注释掉子类中的sing()方法后,便直接调用父类的sing()方法
        c.run();
    }
}

class Parent
{
    public void sing()
    {
        System.out.println("Parent is singing");
    }
}

class Child extends Parent
{   
    //不注释掉则调用子类的
    /*public void sing()
    {
        System.out.println("Child is singing");
    }*/
    public void run()
    {
        System.out.println("Child is running");
    }
}

对于这个程序来说p调用sing方法和c调用sing方法结果是一样的,这里使用向下类型转换是没多大意义。但是子类可以扩展别的方法,比如父类有三个方法,子类添加五个方法(普通或者重写),子类就一共有八个方法这时如果仍使用p,只能调用子类当中存在于父类中声明的那三个方法,而根本调用不了那五个添加的方法,因为p的类型是父类(什么类型的引用类型只能调用什么类型的方法)。所以这时候就必须使用向下类型转换,将它转换成子类型,才能调用添加的那五个方法。这里也体现出重写能实现多态。


疑问?但是向下转型,会不会觉得很傻,我是要用子类实例对象,先是生成子类实例赋值给父类引用,在将父类引用向下强转给子类引用,这不是多此一举吗?我不向上转型也不向下转型,直接用子类实例就行了。
答:这篇博客解释了用到向下转型的一个场景
上面这篇博客很好的解释了为什么要用向下转型,

上面那篇博客的总结,很多时候,我们需要把很多种类的实例对象,全部扔到一个集合。(这句话很重要)
在这个例子里就是把Thinkpad笔记本,Mouse鼠标,KeyBoard键盘等实例对象,全部扔到一个Shopcar购物车集合。
但是肯定不可能给他们每个种类都用一个独立的集合去存放吧,这个时候我们应该寻找到一个标准,接口就是一个标准。这些都是各种电子产品,抽象成电子产品。然后一个Electronics接口就出来了。
在回到刚才,我们把很多种类的实例对象全部扔到一个集合。或许这样比较好理解:把很多种类的子类实例对象全部扔到存放父类实例的集合。
经过了这个过程,子类实例已经赋值给了父类引用(即完成了向上转型),但很遗憾的丢失了子类扩展的方法。
很好的是Java语言有个向下转型的特性,让我们可以重新获得丢失的方法,即强转回子类 ,所以我们需要用到子类实例的时候,就从那个父类集合里拿出来向下转型就可以了,一样可以使用子类实例对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值