若是父类中没有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语言有个向下转型的特性,让我们可以重新获得丢失的方法,即强转回子类 ,所以我们需要用到子类实例的时候,就从那个父类集合里拿出来向下转型就可以了,一样可以使用子类实例对象。