thinking in java笔记 8 多态

邀请您加入新浪APP,享受免费空间、二级域名和域名绑定服务。注册即可获得价值5元的500个云豆奖励。创建的小站每日访客超过2000,通过广告收入补充日常开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
======================================================

多态

多态通过分离做什么和怎么做,从另一角度将接口和实现分离开来。它不但能改善代码的组织结构和可读性,还能创建可扩展的程序。封装通过合并特征和行为来创建新的数据类型,‘实现隐藏’通过将细节私有化把接口和实现分离开来。多态的作用是消除类型之间的耦合关系。多态允许同一基类产生的不同子类之间根据方法的行为不同展现出差别(通过子类覆盖父类的方法实现),而这些方法的调用方式相同。

应用多态,我们所做的代码修改,不会对程序员中其他不应受到影响的部分产生破坏。它帮助我们将改变的事物和未变的事物分离开来。

再论向上转型

把对某个对象的引用视为对其基类型的引用的做法称为向上转型(在继承树的画法中,基类放置在上方)。

若各子类中存在对基类中同一个方法的重载,调用时可以调用其基类方法,然后进行运行时绑定,调用子类方法。

方法调用绑定

将一个方法调用和方法主体关联叫做绑定。

若在程序执行前进行绑定(编译器和连接程序实现),称为前期绑定(如c语言)。

在运行时根据对象的类型进行绑定,称为动态(运行时)绑定(java)。

java除了static方法和final方法(包含private方法)之外,都是动态绑定。

多态的缺陷

只有非private方法可以被覆盖。在导出类中,最好使用和基类中private方法不同的方法名。

域和静态方法不具备多态性。当sub对象转型为super引用时,任何域访问操作都将有编译器解析,因此不是多态的。

静态方法是与类,而非对象关联,因此也不具备多态性。

构造器与多态

基类的构造器总是在导出类的构造过程中被调用,构造器的任务是检查对象是否正确的被构造,而基类中的元素只有在基类的构造器中才能被初始化,只有按照顺序调用才能构建完整对象。

继承与清理

销毁的顺序应该和初始化顺序相反,字段应与声明的顺序相反。对于基类,应先清理导出类,再清理基类。

如果成员对象存在对象共享问题,不能直接清理,这时,须在被共享对象的类中对引用计数,当引用 数为0时再清理。

构造器内部的多态方法的行为

class glyph {

void draw() { print ( "glyph.draw()" ); }

glyph () {

print (

draw();

print (

}

}

class roundglyph extends glyph {

private int radius = 1;

roundglyph( int r) {

radius = r;

print ( "roundglyph.roundglyph(), radius = " + radius );

}

void draw() {

print ( "roundglyph.draw(), radius = " + radius );

}

}

public class polyconstructors {

public static void main(string[] args) {

new roundglyph(5);

}

} /* output:

glyph () before draw()

roundglyph.draw(), radius = 0

glyph () after draw()

roundglyph.roundglyph(), radius = 5

*///:~

glyph ()构造函数中调用 draw()时,会调用 roundglyph的 draw()方法。而此时 radius尚未初始化。

因此,编写构造器时有一个有效准则:只初始化值,尽量避免调用其他方法。

协变返回类型

在导出类的被覆盖方法中可以返回基类方法的返回类型的某种导出类型。

class grain {

public string tostring() { return "grain" ; }

}

class wheat extends grain {

public string tostring() { return "wheat" ; }

}

class mill {

grain process() { return new grain(); }

}

class wheatmill extends mill {

wheat process() { return new wheat(); }

}

用继承进行设计--状态模式

一条通用的准则是:用继承表现行为间的差异,并用字段表达状态上的变化。例子中通过继承得到两个不同的类,用语表达act()之间的差异;而stage通过运用组合使自己的状态发生变化,在这种情况下,这种状态的改变也产生了行为的改变。

import static rasa.util.print.*;

class actor {

public void act() {}

}

class happyactor extends actor {

public void act() { print ( "happyactor" ); }

}

class sadactor extends actor {

public void act() { print ( "sadactor" ); }

}

class stage {

private actor actor = new happyactor();

public void change() { actor = new sadactor(); }

public void performplay() { actor .act(); }

}

public class transmogrify {

public static void main(string[] args) {

stage stage = new stage();

stage.performplay();

stage.change();

stage.performplay();

}

} /* output:

happyactor

sadactor

*///:~

用继承进行设计--纯继承与扩展

纯继承:导出类和基类拥有的方法相同(is-a关系)。导出类可以完全代替基类,使用时,不需要知道关于子类的任何额外信息。只需从导出类向上转型,永远不需要知道正在处理的对象的确切类型。

扩展:导出类像是一个基类,他有着相同的基本接口,但具有由额外方法实现的其他特性。导出类的接口的扩展部分不能被基类访问,因此需要重新查明对象的确切类型,以便能访问该类型的扩充方法。

向上转型会都是具体的类型信息,通过向下转型,能够获取类型信息,但必须保证向下转型的正确性。运行期间会对转型进行检查,以便保证它是我们希望的那种类型(运行时类型识别rtti),若转型错误,会报classcastexception。


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值