您的位置:首页 > 其它

Talk About“Upcasting”[翻译后]

2007-06-15 11:07 519 查看
TalkAbout“Upcasting”
新的类提供方法,并不是inheritance技术中最主要的层面,而最主要的方面是用来表达新的类和基类之间的关系,这种关系可以用一句话概括:“Thenewclassisatypeoftheexistingclass”(我无法对这句经典的描述[<Thinkin’InJava>BruceEckel]进行翻译,以免亵渎Java)
这样的描述并不只是对inheritance一种奇思妙想,JAVA语言直接支持的。例如我们有一个基类“人类”以及一个导出类“男人类”。根据继承的理论,基类所有的方法(函数?[函数就是方法,Java多用方法描述。初学者经常把函数和方法搞不清])在导出类都有效,也就是说,给基类传进去了一个message,在导出类同样可以传向导出类。如果在人类里面有一个sleep()的方法,那么在男人类同样也有sleep()方法,这就意味着男人是人的一种(现实生活中也正是如此!),下面我们就用一个例子来说明编译器是怎么样支持这一概念的:
//file:Human.java

Inheritance&upcasting.

importjava.util.*;


classHuman{

publicvoidsleep(){}

staticvoidbreathe(Humanh){

//...

h.sleep();

}

}


//BoyobjectsareHumans

//becausetheyhavethesameinterface:

publicclassmanextendsHuman{

publicstaticvoidmain(String[]args){

manboy=newman();

Human.breathe(boy);//Upcasting

}

}///:~


有趣的是breathe()方法可以接受一个人类的引用,但是在boy.breathe()中,breathe()方法是通过boy传过去的引用。作为有一个严格类型检查的java语言,接受一个其他类的引用貌似很奇怪,除非你能意识到男人其实就是一个人(现实生活中似乎很简单),其实没有一个方法,如breathe()是通过男人或者人来调用的。在breathe()中的代码作用于基类人类以及任何一个有人类的导出类,这种将boy的类型引用转换成一个Human的引用的“动作”我们叫它“向上转型”。

人类

男人类

[align=center][/align]
为什么叫做“向上转型”?
这个术语是有它的历史原因的,这是基于传统的类继承图的绘制:根节点在最顶端,然后逐渐向下(当然你也可以以任何你认为行之有效的方法来绘制),在human.java里的类继承图如是。
从导出类到基类转型在类继承图里是向上移动的,所以称作“向上转型”,“向上转型”是安全的,因为你是从一个特别制定的比较专用的类型向更加通用的类型转换,换而言之,导出类就是基类的超集,向上转型时,类接口中可能会发生方法的丢失,而不是获取他们,这就是为什么在没有严格指定“我要转型啦!”的时候编译器仍然不报错,允许你这样干。
经过前面的讲解,你已经了看见一个对象是怎么样即作为自身类型的引用,又作为基类型的引用。将一种类型对象的引用视为基类对象的引用的做法叫做“向上转型”,“向上”是因为基类在类继承图的最顶端。但是问题来了,在下面的例子中,到底哪个才是被实例化的呢?既然每一个(人)都要有肤色,我们就应该在包中单独创建一个color类
//:Human:color.java

//EveryOnehasthereskinColor

packagemyApp.human;


publicclasscolor{

privateStringcolorName;

privatecolor(StringcolorName){

this.colorName=colorName;

}

publicStringtoString(){returnnoteName;}

publicstaticfinalcolor

BLACK=newcolor("blackman"),

WHITE=newcolor("whiteman"),

YELLO=newNote("yelloman");

//Etc.

}///:~

这是一个“枚举”类,包含了一定数目的供选择的对象,不能产生额外的对象因为他的构造器是私有的。
下面的例子中,man是Human的一种,所以man可以从Human继承
//:organism.java

//Inheritance&upcasting.

PackagemyApp.Human;



publicclassorganism{

publicstaticvoidbreathe(Humanh){

//...

h.skin(color.BLACK);

}

publicstaticvoidmain(String[]args){

manm=newman();

breathe(m);//Upcasting


});

}

}///:~


//:man.java

packagemyApp.human;


publicclassmanextendsHuman{

//Redefineinterfacemethod:

publicvoidskin(colorc){

System.out.println("man.skin()"+c);

}

}///:~


//:organism.java

//Inheritance&upcasting.

packagemyApp.human;


publicclassorganism{


publicstaticvoidbreathe(humanh){

//...

h.skin(color.WHITE);

}

publicstaticvoidmain(String[]args){

manm=newman();

breathe(m);//Upcasting


}

}///:~


究竟什么时候需要用到继承?
在面向对象时,究竟什么时候需要用到继承?“向上转型”就站出来说话了。
在面向对象编程时,其实用的比较多的方法是将数据和方法简单打包,组合成类,然后使用该类的对象,也可以使用现成的类组合生成一个新的类。其实使用继承的场合是比较少的。因此,尽管在学习OOP时我们多次强调“继承”,但是并不时意味着你就要不加选择的使用它(那叫滥用),相反,你应该慎用!除非你确定非使用此项技术不可。方法很简单明了:问一问自己是否真的需要从导出类向基类转型,如果需要,那必然使用继承,否则你应该仔细推敲自己是否需要使用到继承。此时,如果你能记得问问自己“我需要用到向上转型吗?”这样子你就能很轻松的从组合和继承这两种技术之间作出决定。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: