在被众多的向上转型的题弄晕之后,我选择去彻底弄懂它。
1.什么是向上转型?
先看一段代码
<span style="font-size:18px;">class Fruit{
public void eat(){</span>
<span style="font-size:18px;"><span style="white-space:pre"></span></span><pre name="code" class="java"><span style="white-space:pre"> </span>System.out.println("you are eating some fruit");
}
<span style="font-size:18px;"> public static void pick(Fruit fruit){</span>
<span style="font-size:18px;"><span style="white-space:pre"></span></span><pre name="code" class="java"><span style="white-space:pre"> </span>System.out.println("pick fruit");
}
}public class Apple{
<span style="font-size:18px;"> public void eat(){</span>
<span style="font-size:18px;"><span style="white-space:pre"> </span>System.out.println("you are eating an apple");</span>
<span style="font-size:18px;"> }</span>
<span style="font-size:18px;"> public void price(){</span>
<span style="font-size:18px;"></span><pre name="code" class="java"><span style="font-size:18px;"><span style="white-space:pre"> </span>System.out.println("apple is cheap");</span>
<span style="font-size:18px;"> }</span>
public static void main(String[] args){
<span style="font-size:18px;"><span style="white-space:pre"> </span>Fruit fruit = new Apple();</span>
<span style="font-size:18px;"> }</span>
<span style="font-size:18px;">}</span>
其中Fruit() fruit = new Apple();就是向上转型,指的是父类引用指向子类对象。一般来说,父类是在上面的,它的子类或者子类的子类都是由它派生出来的,都是在它的下面,把一个Apple对象当成Fruit对象引用的时候,表现出一个箭头由下指向上,所以就有向上转型的说法。
2.向上转型的使用
2.1子类对象代替父类对象
如果你在main方法里加一句Fruit.pick(new Apple());肯定会输出pick fruit的,很多人或许会奇怪,Java具有严格的类型检查,明明需要传入一个fruit类型的对象却在传入apple对象时也可以?你可以这样理解,apple是fruit的子类,fruit中所有的变量和方法apple中都有,并且可能还自身扩展了一些变量和方法。编译器在编译时将fruit转换成apple,只会“丢掉”一些方法和变量,而不是获取。这是完全可以的。
2.2父类引用调用子类方法
如果在main中调用eat方法,即fruit.eat();,结果输出的是you are eating an apple。虽然是父类的引用,可是在运行时,引用指向堆中的apple对象时,发现apple子类有重写父类的eat方法,就调用了子类重写后的方法。若子类没有重写父类的方法,则调用的是父类的方法。
如果main中有fruit.price();,结果是编译器会立马提示错误。因为编译器并没有在父类中找到该方法。
关于父类引用调用子类方法,在编译时是,根据父类的引用去查找父类中有没有改方法,即编译期绑定;而在运行时,根据子类的对象去堆中寻找合适的方法,即运行期绑定。一句话,可不可以用是通过父类引用知道,到底用哪个是根据子类对象知道的。
3.向上转型的好处
将上述父类Fruit中pick方法改为pick(Apple apple),那如果我还有一个Orange类,同样继承Fruit的话,那orange调用pick方法时,就要有一个pick(Orange orange)方法了,要是还有一种水果,就还要有一种pick方法,这样写起来太过繁琐。Java提供了众多的API就是为了细致的划分工作,寻找适合的API可以提高程序运行的效率。
向上造型也是Java多态的一种体现!
<span style="white-space:pre"> </span>