Talk About“Upcasting”[翻译后]

 
Talk About“Upcasting”
新的类提供方法,并不是inheritance技术中最主要的层面,而最主要的方面是用来表达新的类和基类之间的关系,这种关系可以用一句话概括:“The new class is a type of the existing class”(我无法对这句经典的描述[<Thinkin’InJava>BruceEckel]进行翻译,以免亵渎Java)
这样的描述并不只是对inheritance一种奇思妙想,JAVA语言直接支持的。例如我们有一个基类“人类”以及一个导出类“男人类”。根据继承的理论,基类所有的方法(函数?[函数就是方法,Java多用方法描述。初学者经常把函数和方法搞不清])在导出类都有效,也就是说,给基类传进去了一个message,在导出类同样可以传向导出类。如果在人类里面有一个sleep()的方法,那么在男人类同样也有sleep()方法,这就意味着男人是人的一种(现实生活中也正是如此!),下面我们就用一个例子来说明编译器是怎么样支持这一概念的:
//file:Human.java
 Inheritance & upcasting.
import java.util.*;
 
class Human {
 public void sleep() {}
 static void breathe(Human h) {
    // ...
    h.sleep();
 }
}
 
// Boy objects are Humans
// because they have the same interface:
public class man extends Human {
 public static void main(String[] args) {
   man boy = new man();
    Human.breathe(boy); // Upcasting
 }
} ///:~
 
有趣的是breathe()方法可以接受一个人类的引用,但是在boy.breathe()中,breathe()方法是通过boy传过去的引用。作为有一个严格类型检查的java语言,接受一个其他类的引用貌似很奇怪,除非你能意识到男人其实就是一个人(现实生活中似乎很简单),其实没有一个方法,如breathe()是通过男人或者人来调用的。在breathe()中的代码作用于基类人类以及任何一个有人类的导出类,这种将boy的类型引用转换成一个Human的引用的“动作”我们叫它“向上转型”。

人 类
男人类

        
为什么叫做“向上转型”?
这个术语是有它的历史原因的 ,这是基于传统的类继承图的绘制:根节点在最顶端,然后逐渐向下(当然你也可以以任何你认为行之有效的方法来绘制),在human.java里的类继承图如是。
从导出类到基类转型在类继承图里是向上移动的,所以称作“向上转型”,“向上转型”是安全的,因为你是从一个特别制定的比较专用的类型向更加通用的类型转换,换而言之,导出类就是基类的超集,向上转型时,类接口中可能会发生方法的丢失,而不是获取他们,这就是为什么在没有严格指定“我要转型啦!”的时候编译器仍然不报错,允许你这样干。
经过前面的讲解,你已经了看见一个对象是怎么样即作为自身类型的引用,又作为基类型的引用。将一种类型对象的引用视为基类对象的引用的做法叫做“向上转型”,“向上”是因为基类在类继承图的最顶端。但是问题来了,在下面的例子中,到底哪个才是被实例化的呢?既然每一个(人)都要有肤色,我们就应该在包中单独创建一个color类
//: Human:color.java
// EveryOne has there skinColor
package myApp.human;
 
public class color {
 private String colorName;
 private color(String colorName) {
    this.colorName = colorName;
 }
 public String toString() { return noteName; }
 public static final color
    BLACK = new color("black man"),
    WHITE = new color("white man"),
    YELLO   = new Note("yello man");
    // Etc.
} ///:~
这是一个“枚举”类,包含了一定数目的供选择的对象,不能产生额外的对象因为他的构造器是私有的。
下面的例子中,man是Human的一种,所以man可以从Human继承
//: organism.java
// Inheritance & upcasting.
Package myApp.Human;
 
 
public class organism {
 public static void breathe(Human h) {
    // ...
    h.skin(color.BLACK);
 }
 public static void main(String[] args) {
    man m = new man();
    breathe(m); // Upcasting
   
    });
 }
} ///:~
 
//: man.java
package myApp.human;
 
public class man extends Human {
 // Redefine interface method:
 public void skin(color c) {
    System.out.println("man.skin() " + c);
 }
} ///:~
 
//: organism.java
// Inheritance & upcasting.
package myApp.human;
 
public class organism {
 
  public static void breathe(human h) {
    // ...
    h.skin(color.WHITE);
 }
 public static void main(String[] args) {
    man m = new man();
    breathe(m); // Upcasting
 
  }
} ///:~
 
究竟什么时候需要用到继承?
在面向对象时,究竟什么时候需要用到继承?“向上转型”就站出来说话了。
在面向对象编程时,其实用的比较多的方法是将数据和方法简单打包,组合成类,然后使用该类的对象,也可以使用现成的类组合生成一个新的类。其实使用继承的场合是比较少的。因此,尽管在学习OOP时我们多次强调“继承”,但是并不时意味着你就要不加选择的使用它(那叫滥用),相反,你应该慎用!除非你确定非使用此项技术不可。方法很简单明了:问一问自己是否真的需要从导出类向基类转型,如果需要,那必然使用继承,否则你应该仔细推敲自己是否需要使用到继承。此时,如果你能记得问问自己“我需要用到向上转型吗?”这样子你就能很轻松的从组合和继承这两种技术之间作出决定。
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值