Java继承.docx

上传人:b****6 文档编号:6818254 上传时间:2023-01-10 格式:DOCX 页数:14 大小:24.52KB
下载 相关 举报
Java继承.docx_第1页
第1页 / 共14页
Java继承.docx_第2页
第2页 / 共14页
Java继承.docx_第3页
第3页 / 共14页
Java继承.docx_第4页
第4页 / 共14页
Java继承.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

Java继承.docx

《Java继承.docx》由会员分享,可在线阅读,更多相关《Java继承.docx(14页珍藏版)》请在冰豆网上搜索。

Java继承.docx

Java继承

我们将向你展示JavaScript如何实现面向对象的语言中的:

继承.同时,这些例子将向你展示如何实现类的封装.在此,我们不会讨论多态实现.

  虽然JavaScript是脚本语言,但它所支持的面向对象编程也是非常强大的.虽然它没有类和实例,但它有对象,原型和隐式的继承.我们将会解释如何模拟继承及其超类与子类之间关系的形式.原型是理解继承概念的关键,我们将会教你如何建立原型,如何检测一个对象是否是另外一个对象的原型,及其JavaScript的模型与Java面向对象编程之间的区别.我们同样会向你展示如何检测对象所包含的各种属性的方法.在另外一篇文章里,我还会详细地讲解有关"原型链(prototypechain)"的知识.

  本文大量地参考了W中"Object-OrientedProgrammingwithJavaScript,PartI:

Inheritance"的内容,许多内容我进行了详细的测试和再探讨,以保证内容不会有太大的失误.

原文地址:

  面向对象语言的特点

  面向对象设计是基于以下3个主要原理的:

封装,继承和多态.说某种程序语言是支持OO(面向对象)设计的,只有在它的语法中支持以上3个概念才可以这么说.这种语言应该为你提供某些方法,以使你能很轻松地定义和使用这些范例.封装涉及到了将某个对象变成一个"黑盒子"的概念.当你使用某个对象时,你不用知道它内部是如何工作的,你也不必理解对象是如何工作的.这个对象只需将它绝对有用的信息以接口方式提供出来.此对象应该给你提供友好的接口,来让你可以使用其有限的属性集和方法集.封装还有一层意思,那就是说某个对象包含了它需要的每一样东西,这包括数据和对于它的操作.封装的概念非常的强大,因为它允许将一个大的软件项目有效地分配给每个开发人员,对于团队中的每个人,他们只需要关注自己所实现的对象,而不需要太多地关注于别人的实现.开发项目中的开销使得开发团队中成员与接口的数量按指数级别增长.封装是自"软件危机"以来最受欢迎的OO设计理念.

  软件的复用是OO设计思想中另外一个重要的特点.在软件体系中实现此思想的主要方法就是继承.类就是定义对象的功能.超类是某个新类,或者说是子类被建立的来源类.一个子类从它的超类中继承了所的方法和属性.实际上,所有的子类都是被自动地生成的,因此节省了大量的工作.你不需要一个一个地定义这些子类.当然,你可以重载那些继承下来的方法和属性.事实上,谁也没有指出哪个子类要建立得和其超类一模一样,除非你没有重载任何的属性和方法.

  多态可能是这个3个概念中最复杂的一个了.其本质上是说,每个对象都可以处理各种不同的数据类型.你不必为处理不同的数据类型而建立不同的类.其典型的例子就是画图的类,你不必为实现画圆,画矩形,画椭圆而编写不同的类.你可以建立一个足够聪明的类来调用特定的方法来操作特定的形状.

  通过函数实现继承

  虽然JavaScript不支持显示继承操作符,但你可以通过其实方式实现隐式继承.对于实现类的继承,有2种比较常用的方式.第一种将某个类定义成子类的方法是,通过在负责定义子类函数的内部调用超类的构造函数.看下面的示例:

//超类构造函数

functionsuperClass(){

this.bye=superBye;

this.hello=superHello;

}

//子类构造函数

functionsubClass(){

this.inheritFrom=superClass;

this.inheritFrom();

this.bye=subBye;

}

functionsuperHello(){

return"HellofromsuperClass";

}

functionsuperBye(){

return"ByefromsuperClass";

}

functionsubBye(){

return"ByefromsubClass";

}

//测试构造特性的函数

functionprintSub(){

varnewClass=newsubClas

欢迎光临学网,收藏本篇文章[1][2][3][4][5][6][7][8]

$False$

s();

alert(newClass.bye());

alert(newClass.hello());

}

  当你运行上面的printSub函数时,它会依次执行subBuy和superHello函数.我们可以看到,bye和hello方法最先在superClass中被定义了.然而,在subClass中,bye方法又被重载了,subClass构造函数头两行的功能只是做了一个简单的原始的继承操作,但它是通过显示执行inheritFrom方法来完成的继承操作.继承的过程先是将superClass的对象原型赋给subClass下的inheritFrom方法,然后在执行完superClass的构造函数后,superClass的属性就被自动地加到了subClass的属性列表中.这主要是由于在subClass中通过this来调用的inheritFrom(也就是superClass)构造函数造成的,通过此种方式调用superClass构造函数时,JavaScript解释器会把superClass中的this与subClass中的this理解成位于同一个作用域下的this关键字,所以就产生了继承的效果.

  另外,需要说明的是,对于任何一个实例化的对象,你任意地为它添加属性或方法,如下所示:

varnewClass=newsubClass();

newClass.addprop="addedpropertytoinstanceobject";

  很明显,通过此种方式添加的属性和方法只对当前实例化对象有效,不会影响所有的同类型对象实例.无疑,它是你创造的一个独一无二的对象实例.

  通过原型实现继承

  第二种,也是更强大的方法是通过建立一个超类对象,然后将其赋值给子类对象的prototype属性,以此方式来建立子类的继承.假设我们的超类是superClass,子类是subClass.其prototype的赋值格式如下:

subClass.prototype=newsuperClass;

对于原型继承的实现方式,让我们刚前面的代码改写一下,示例如下:

//超类构造函数

functionsuperClass(){

this.bye=superBye;

this.hello=superHello;

}

//子类构造函数

functionsubClass(){

this.bye=subBye;

}

subClass.prototype=newsuperClass;

functionsuperHello(){

return"HellofromsuperClass";

}

functionsuperBye(){

return"ByefromsuperClass";

}

functionsubBye(){

return"ByefromsubClass";

}

//测试构造特性的函数

functionprintSub(){

varnewClass=newsubClass();

alert(newClass.bye());

alert(newClass.hello());

}

  我们可以看到,除了将前面第一种继承方式中subClass中的前2行内容,换成函数外的prototype赋值语句之外,没有其它任何的变化,但代码的执行效果和前面是一样的.

  为已经建立的对象添加属性

  通过原型实现的继承比通过函数实现的继承更好,因为它支持动态继承.你可以在构造函数已经完成之后,再通过prototype属性定义超类的其它方法和属性,并且其下的子类对象会自动地获得新的方法和属性.下面是示例,你可以看到它的效果.

functionsuperClass(){

this.bye=superBye;

this.hello=superHello;

}

functionsubClass(){

this.bye=subBye;

}

subClass.prototype=newsuperClass;

functionsuperHello(){

return"HellofromsuperClass";

}欢迎光临学网,收藏本篇文章[1][2][3][4][5][6][7][8]

functionsuperBye(){

return"ByefromsuperClass";

}

functionsubBye(){

return"ByefromsubClass";

}

varnewClass=newsubClass();

/*****************************/

//动态添加的blessyou属性

superClass.prototype.blessyou=superBlessyou;

functionsuperBlessyou(){

return"BlessYoufromSuperClass";

}

/*****************************/

functionprintSub(){

alert(newClass.bye());

alert(newClass.hello());

alert(newClass.blessyou());

}

  这就是我们经常看到的为内部对象,如String,Math等再添加其它属性和方法的技巧.对于任何的内部对象和自定义对象,你都也可以通过prototype来重载其下的属性和方法.那么在调用执行时,它将调用你所定义的方法和属性.下面是示例:

//为内部String对象添加方法

String.prototype.myMethod=function(){

return"mydefinemethod";

}

//为内部String对象重载方法

String.prototype.toString=function(){

return"mydefinetoStringmethod";

}

varmyObj=newString("foo");

alert(myObj.myMethod());

alert(myObj);

alert("foo".toString());

  另外需要注意的是,所有JavaScrip

t内部对的prototype属性都是只读的.你可以像上面那样为内部对象的原型添加或重载属性和方法,但不能更改该内部对象的prototype原型.然而,自定义对象可以被赋给新的原型.也就是说,像下面这样做是没有意思的.

functionEmployee(){

this.dept="HR";

this.manager="JohnJohnson";

}

String.prototype=newEmployee;

varmyString=newString("foo");

上面的程序在运行之后不会报错,但显然,如果你调用myString.dept将会得到一个非定义的值.

另外,一个经常使用的是prototype下的isPrototypeOf()方法,它主要用来判断指定对象是否存在于另一个对象的原型链中.语法如下:

object1.prototype.isPrototypeOf(0bject2);

上面的格式是用来判断Object2是否出现Object1的原型链中.示例如下:

functionPerson(){

this.name="RobRoberson";

this.age=31;

}

functionEmployee(){

this.dept="HR";

this.manager="JohnJohnson";

}

Employee.prototype=newPerson();

varKen=newEmployee();

当执行Employee.prototype.isPrototypeOf(Ken),Person.prototype.isPrototypeOf(Ken)和Object.prototype.isPrototypeOf(Ken)时,结果都会返回true.

  用于Netscape下的特定继承检测

  在Netscape浏览器4.x到6,及其Mozilla系列浏览中,JavaScript将对象间的原型关系存储在一个特殊的内部属性对象中,__proto__(前后是2个下划线).下面是一个示例:

functionShape(){

this.borderWidth=5;

}

欢迎光临学网,收藏本篇文章[1][2][3][4][5][6][7][8]

functionSquare(){

this.edge=12;

}

Square.prototype=newShape;

myPicture=newSquare;

alert(myPicture.__proto__);

alert(myPicture.borderWidth);

  由于脚本执行过Square.prototype=newShape语句,所以myPicture具有了一个指向Shape对象的内部属性__proto__.在脚本的执行过程中,当要获取对象的某个属性值,并且此对象是通过原型赋值而建立的某个对象,在自身并没有对某个属性进行定义时,JavaScript解析器会查看它的__proto__属性对象,也就它的原型对象,然后枚举其原型中的所有属性,而得出的结果要么是有这个属性,要么是没有这个属性.如果没有此属性,再枚举原型对象下面的原型对象,直到此过程真正的结束.而所有的这些JavaScript引擎内部的操作,我们是不会知道的,下面的内容就是对这个问题的解释.

  其实,对于所有的自定义对象,无论它有没有使用过prototype赋值操作,它都具有一个__proto__内部对象.而如果某个对象是通过多层prototype"继承"来的,所有的"继承"而来的属性却可以通过简单的一层循环遍历出来,而不需要使用什么递归算法,因为JavaScript引擎自动给我们做了.示例如下:

functionShape(){

this.borderWidth=5;

}

functionSquare(){

this.edge=12;

}

functionRoundSquare()

{

this.radio=0.5;

}

Square.prototype=newShape;

RoundSquare.prototype=newSquare;

varmyPicture=newRoundSquare;

for(propertyinmyPicture.__proto__){

alert(property);

}

  我们或者还可以通过更改后面的循环,来遍历某个子类对象继承来的所有属性,如下:

for(propertyinRoundSquare.prototype){

alert(property);

}

  如果你不怕麻烦,我们甚至还可以通过级连的方式,取出其构造函数中定义的原始属性值.

alert(myPicture.__proto__.__proto__.borderWidth);

  无论你是否修改过此属性值,通过上面语句所取出的属性值都是原始定义值.让我们沿着这个思路再往下看,下面的代码涉及到另外一个问题,这个问题和原型链(prototypechain)有关.代码如下:

functionState(){

}

functionCity(){

}

City.prototype=newState;

functionStreet(){

}

Street.prototype=newCity;

varUniversityAvenue=newStreet();

functiontryIt(){

alert(UniversityAvenue.__proto__==Street.prototype);

alert(UniversityAvenue.__proto__.__proto__==

City.prototype);

alert(UniversityAvenue.__proto__.__proto__.__proto__

==State.prototype);

alert(UniversityAvenue.__proto__.__proto__.__proto__.

__proto__==Object.prototype);

alert(UniversityAvenue.__proto__.__proto__.__proto__.

__proto__.__proto__==null);

}

  当执行tryIt函数时,所有的显示均为true.也就是说,子类对象的prototype.__proto__总是等于超类对象的prototype属性;超类对象的prototype.__proto__总是等于Object.proto文章整理:

学网(本站)[1][2][3][4][5][6][7][8]

type;Object.prototype.__proto__总是为null;而实例对象的__proto__总是等于其类对象的prototype,这就是为什么任何自定义对象都具有__proto__属性的原因.对于上面的叙述,其对应的代码如下:

Street.prototype.__proto__==City.prototype//true

State.prototype.__proto__==Object.prototype//true

Object.prototype.__proto__==null//true

UniversityAvenue.__proto__==Street.prototype//true

  模拟实现instanceOf函数

  根据上一节的内容,我们了解了有关Netscape所支持的__proto__特性的内容.这一节,我们将利用此特性来创建自己的实例对象检测函数.

  许多时候,我们都需要判断某个对象是否是由某个类来定义的,在其它的语言里,你可以通过instanceOf函数来实现此判断.在JavaScript中同样提供了一个instanceof运行符,而在__proto__的基础上,我们完全可以自己定义一个同样的函数,虽然这看上去是在重复劳动,但有助于我们更深刻地了解有关__proto__的知识.下面的代码只是用来说明功能,在实际的应用中,你不需要重复定义instanceOf函数,使用instanceof运算符即可.

functioninstanceOf(object,constructorFunction){

while(object!

=null){

if(object==constructorFunction.prototype)

{returntrue}

object=object.__proto__;

}

returnfalse;

}

functionState(){

}

functionCity(){

}

City.prototype=newState;

functionStreet(){

}

Street.prototype=newCity;

varUniversityAvenue=newStreet();

functiondemo(){

alert("instanceOf(UniversityAvenue,Street)is"+

instanceOf(UniversityAvenue,Street));

alert("instanceOf(UniversityAvenue,City)is"+

instanceOf(UniversityAvenue,City));

alert("instanceOf(UniversityAvenue,State)is"+

instanceOf(UniversityAvenue,State));

}

  你会看到所有的运行结果全部为true,其原理和上一节的级连判断相等如出一辙.实际证明,它的运行结果和instanceof运行符的运行结果是一致的.

  你可以通过constructor属性来检测任意对象的超类,此属性返回通过new运算符创建新对象时所调用的构造函数,返回值是Function对象类型.因为Object内部对象是支持constructor属性的,并且有的对象(包括内部对象和自定义对象)都是由Object继承而来的,所以所有的对象都支持此属性.让我们再看一下下面的例子:

functionEmployee(){

this.dept="HR";

this.manager="JohnJohnso

n";

}

functionprintProp(){

varKen=newEmployee();

alert(Ken.constructor);

}

欢迎光临学网,点击这里查看更多文章教程[1][2][3][4][5][6][7][8]

  调用完printProp函数之后,你会看到弹出框中显示的是Employee函数的定义文本,其实Ken.constructor的返回值本身是Function对象类型,而在alert时被隐含地调用了t

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 制度规范

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1