Read Sean
Read me, read Sean.
posts - 508, comments - 655, trackbacks - 9, articles - 4
导航
BlogJava
首页
新随笔
联系
聚合
管理
公告
关于我
人生是一场对话
我的译作
声明
所有文章和代码在这里以"现状"提供,作者不提供任何形式的担保,也没有授予除阅读和有条件共享之外的任何权利。除非特别说明,所有文章均为本blog作者原创,如需转载请注明出处和原作者,如用于商业目的,需作者本人书面许可。
推荐文章
Pylons起步
常用链接
我的随笔
我的评论
我的参与
最新评论
留言簿
(29)
给我留言
查看公开留言
查看私人留言
随笔分类
(842)
Computer Usage(72)
Database(9)
GNU/Linux(30)
On Eclipse(52)
On Java(131)
On Python(11)
Operating Systems(70)
Other Languages(28)
Programming in General(41)
Project Management(25)
Reading(189)
The Other Side(129)
Web Clips(55)
随笔档案
(507)
2014年5月 (1)
2014年4月 (1)
2014年3月 (1)
2014年1月 (1)
2012年11月 (1)
2011年8月 (2)
2011年7月 (1)
2011年3月 (1)
2011年2月 (2)
2011年1月 (5)
2010年12月 (2)
2010年1月 (1)
2009年12月 (1)
2009年11月 (1)
2009年10月 (1)
2009年9月 (1)
2009年8月 (1)
2009年7月 (1)
2009年6月 (2)
2009年5月 (1)
2009年4月 (1)
2009年3月 (2)
2009年2月 (2)
2009年1月 (15)
2008年12月 (10)
2008年11月 (1)
2008年10月 (4)
2008年9月 (1)
2008年8月 (3)
2008年7月 (3)
2008年6月 (2)
2008年5月 (2)
2008年4月 (1)
2008年3月 (4)
2008年2月 (5)
2008年1月 (4)
2007年12月 (2)
2007年11月 (2)
2007年10月 (1)
2007年9月 (1)
2007年8月 (2)
2007年7月 (2)
2007年6月 (4)
2007年5月 (3)
2007年4月 (5)
2007年3月 (4)
2007年2月 (23)
2007年1月 (26)
2006年12月 (30)
2006年11月 (14)
2006年10月 (6)
2006年9月 (2)
2006年8月 (3)
2006年7月 (3)
2006年6月 (5)
2006年5月 (3)
2006年4月 (17)
2006年3月 (9)
2006年2月 (28)
2006年1月 (17)
2005年12月 (8)
2005年11月 (23)
2005年10月 (43)
2005年9月 (19)
2005年8月 (30)
2005年7月 (13)
2005年6月 (7)
2005年5月 (5)
2005年4月 (12)
2005年3月 (20)
2005年2月 (19)
2005年1月 (8)
文章档案
(4)
2010年12月 (1)
2009年1月 (1)
2005年8月 (1)
2005年1月 (1)
Friends' blogs
emu in blogjava
jackei
kukoo's blog
搜索
积分与排名
积分 - 775571
排名 - 55
最新评论
1. re: [Tips] <abbr>: 一个有趣的HTML标签
dqwdqwdqw
--额范围啊
2. re: [Tips] <abbr>: 一个有趣的HTML标签
<scrtpt>alert("fwefwargvaerg");</script>
--额范围啊
3. re: iText vs FOP - Java动态生成PDF的两个选择
用0.95报错的大概意思是还不支持。。。。。
本地字库的字体embet不进去。。。。
--fop
4. re: iText vs FOP - Java动态生成PDF的两个选择
代码拷贝运行报错啊
--fop
5. 11[未登录]
404
--00
6. re: [Tips] Spring 2.5.6新特性之packagesToScan
101
--11
7. re: Mac安装tsocks
评论内容较长,点击标题查看
--mzj
8. re: [Jakarta Commons笔记] org.apache.commons.lang.time
哈哈,什么情况,10年前的文章,今天来读一读
--宇飞
9. re: Mac安装tsocks
有一个proxychains-ng项目,还在更新,可以试试的
--ayanamist
10. re: SourceForge.net上的文件下载页面无法打开的一种解决方法
评论内容较长,点击标题查看
--Douglas
11. re: [Tips] Windows/Linux双系统重装Windows后无法进入Linux的最速解决办法
linux是进去了,windows又进不去了
--ss
12. re: [RPi] 树梅派安装Archlinux和蓝牙
这种便宜dongle有个问题就是蓝牙MAC地址是一样的,同一环境下使用多个会有点麻烦,需要找个办法绕过去。
--laogao
13. re: [愚公移山] 团队CVS资源库从CVSNT迁移到Linux
评论内容较长,点击标题查看
--guest
14. re: [Jakarta 笔记] org.apache.commons.lang.math[未登录]
评论内容较长,点击标题查看
--doctor
15. re: Jakarta Commons专题 - 随笔列表
可惜晚了这么多年,才读到楼主的文章。
--rox
阅读排行榜
1. [Tips] 恼人的winmail.dat及解决办法(36602)
2. [Eclipse笔记]在Eclipse下做UML设计(28382)
3. [Tips] Spring 2.5.6新特性之packagesToScan(22711)
4. iText vs FOP - Java动态生成PDF的两个选择(13707)
5. IntelliJ IDEA 常用快捷键(12873)
6. pyPdf - 用Python方便的处理PDF文档(12623)
7. [Linux起步]配置Java和Eclipse环境(9852)
8. Java命令行实用工具jps和jstat(9468)
9. 你真的理解了继承和多态吗?(7663)
10. [Eclipse笔记]配置SWT开发环境(7525)
11. Drip, Transfusion, Perfusion还是Infusion?关于一个词的翻译(7445)
12. [Jakarta Commons笔记] org.apache.commons.lang.time(7346)
13. 如何在Ubuntu下访问本地NTFS分区(6486)
14. [Jakarta Commons笔记] org.apache.commons.lang.builder(6078)
15. J2SE(TM) 5.0专题 之 语言特性 // 勘误信息请直接回复(5731)
评论排行榜
1. [Tips] 恼人的winmail.dat及解决办法(48)
2. 6个Gmail邀请,需要的朋友请在这里回复。(已结束)(34)
3. [Eclipse笔记]在Eclipse下做UML设计(29)
4. [Eclipse笔记]请对Java、Sun、NetBeans、Eclipse感兴趣朋友的看看Eclipse对Sun的心态吧(19)
5. 令人惊喜的Feisty,让人失望的Evolution(15)
6. 你真的理解了继承和多态吗?(14)
7. [Jakarta Commons笔记] org.apache.commons.lang.time(11)
8. iText vs FOP - Java动态生成PDF的两个选择(11)
9. [Eclipse笔记]SWT真正的优势不是快这么简单(9)
10. [Linux起步]SuSE Linux 10.0正式发布(9)
11. Drip, Transfusion, Perfusion还是Infusion?关于一个词的翻译(8)
12. [Tips] 在Ubuntu Linux 6.06 LTS (Dapper Drake)上安装CVS服务(8)
13. Nikon F80 + AF Nikkor 50mm/1.4 D 的魅力(8)
14. [Linux起步]配置Java和Eclipse环境(7)
15. J2SE(TM) 5.0专题 之 语言特性 // 勘误信息请直接回复(7)
你真的理解了继承和多态吗?
Posted on 2005-06-07 15:18
laogao
阅读(7663)
评论(14)
编辑
收藏
所属分类:
On Java
、
Programming in General
最近被同事问起一道SCJP的题目,是跟继承和多态有关的。具体的题目我就不重复了,来看一段我自己敲的代码:
1
package sean.work.test;
2
3
public
class
DoYouReallyUnderstandPolymorphism
{
4
5
public
static
void
main(String[] args)
{
6
A a
=
new
A();
7
B b
=
new
B();
8
a.s
=
"
[AA]
"
;
9
b.s
=
"
[BB]
"
;
10
System.
out
.println(a.s);
//
prints "[AA]"
11
System.
out
.println(b.s);
//
prints "[BB]"
12
System.
out
.println(a.getS());
//
prints "[AA]"
13
System.
out
.println(b.getS());
//
prints "[BB]"
14
System.
out
.println(
"
====================
"
);
15
a
=
b;
//
a now refers to object b
16
System.
out
.println(a.s);
//
prints "[A]" <<--1-- the class A copy
17
System.
out
.println(b.s);
//
prints "[BB]"
18
System.
out
.println(a.getS());
//
prints "[BB]"
19
System.
out
.println(b.getS());
//
prints "[BB]"
20
System.
out
.println(
"
====================
"
);
21
((A)b).s
=
"
[AA]
"
;
//
<<--2-- changes the class A copy in object b
22
System.
out
.println(a.s);
//
prints "[AA]" <<--3-- class A copy changed
23
System.
out
.println(b.s);
//
prints "[BB]"
24
System.
out
.println(a.getS());
//
prints "[BB]"
25
System.
out
.println(b.getS());
//
prints "[BB]"
26
}
27
28
}
29
30
class
A
{
31
String s
=
"
[A]
"
;
32
String getS()
{
33
return
s;
34
}
35
}
36
37
class
B extends A
{
38
String s
=
"
[B]
"
;
39
String getS()
{
40
return
s;
41
}
42
}
43
这里我们的B类继承自A类,重写了getS()方法,于是我们可以利用到多态。如果你留意15、16、21、22这几行的话,你也许就会知道我在说什么了。假如你觉得这样的打印结果是理所当然,那么我想你可以完全忽略这篇随笔,因为我要讲的就集中在这几行,而你已经很清楚的理解背后的含义。
下面跟感兴趣的朋友们说说我的理解:
直观的讲,我们很容易轻信当"a = b;"以后,变量a指向的对象是B类的b那个对象,自然a.s就应该等同于b.s,然而事实并非如此。当B继承A时,父类A的字段s并没有被B的字段s取代,而是保留了一份拷贝,所谓重写(Override),那是对方法而言的。于是,当我们new B()时,在实际创建的对象中,包含了两个版本的字段s,一个"[A]"(属于A类)一个"[B]"(属于B类)。而方法getS()只有一个版本。这就是在继承过程中字段和方法的区别。也就是说,重写的概念和字段无关。在第16行,我们通过a.s访问的是b这个对象中保留的A类的字段s;而在21行,我们改变的正是这个A类版本的s字段。
多态的精髓在于动态确定对象的行为,而对象的行为体现在方法而非字段,字段代表的更多的是对象的状态。于是只有方法的多态而没有字段的多态。从上面的代码可以看出,不管你用什么类型的变量存放对象b的引用,最终调用的方法版本都是b的真实类型那个版本,这就是多态的威力。
从编译的角度来看,上面代码中的s字段和getS()方法的不同在于:s字段是在编译期静态链接(你可以改变它的值,但是它在对象中的相对地址已经确定好),而getS()方法是在运行期动态链接的。
说了这么多,真的不知道我表达清楚没有,毕竟没有系统研究过OO和编译原理,说得不当的地方还请多多包涵。最后,请不要学我这里的编码风格,因为很显然应该对main方法中的代码段执行Extract Method重构了,我这里只是为了注释方便。
// BTW,时不时抽空想想这样的问题感觉真不错。
Feedback
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2005-06-07 16:26 by
小毅
谢谢您,学到很容易忽略的东西,觉得很重要
再谢谢你...
#
原来字段和方法有这样的区别哦
回复
更多评论
2005-06-08 09:02 by
emu
>>只有方法的多态而没有字段的多态
以前都没有想过这个问题哦。
前两天遇到一个内嵌类的方法重载时候的古怪问题,不知是否与此有关,正好回头去研究一下。
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2005-06-08 12:16 by
FS
Java的对象模型偶不太清楚,不过通过对Delphi的对象模型的了解,我感觉应该和Java没有太大的区别。
按照楼主所说的,当执行了语句“a=b”后,变量a和b的内容应该是不变的,所变的是a指向的对象实体中的指向类的指针的内容,在Delphi中,这个指针叫做vptr,CPP中也是如此叫法。vptr直接指到类的VMT(不知道Java中如何叫法);因此,再次使用a.s访问实例变量,则要进入b指向的对象实体中进行字段的查找,但由于b里面存在两个s字段,并且以类型信息为区分方式,所以找到的是类型A的字段s。至于编译处理方面,我想应该是把类型信息作为字段的前缀或者后缀。
同样,当执行了“((A)b).s=“[AA]””后,由于已经把b的类型转化为A类型,而且b指针的未改变,所以在b的对象实体中,实际改变的是属于类型A的字段s的内容。个人感觉,其实楼主已经说出了,对b中不同类型的同名字段的访问方式。
最后留下一个问题:这种对象模型中的字段处理方式如果在继承字段访问量小的情况下是很浪费空间的。那么,这样处理的优点又是什么?
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2005-06-08 12:18 by
FS
按照OO这种东西在语言设计上的考虑,对象所涉及到的所有内容就是三块:对象指针,对象实体和对象所属类型的内存布局。而对象实体中只存放状态信息,即对象所属类型的实例字段的内容,因此,从这个角度考虑,多态和实例字段的信息是没有任何关系的。但对于类字段,即申明为static的字段就未必了。
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2005-07-20 23:24 by
丑男
System.out.println(a.s); // prints "[A]"
这句确实我没想到!看来真被难倒了
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2006-05-15 17:30 by
songxu
非常感谢
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2006-07-15 17:22 by
tcpipok
我是想到了,不过就像楼主所说的,这种编码风格不好,子类尽量不要用父类用过的变量名,真的是容易搞混,这种代码用来考试可以,但用来编程不好.
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2006-08-17 20:34 by
小小
请问:
java中字符串的连接是不是一种多态的表现?
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2007-03-05 22:52 by
谷钰
@tcpipok
我不知道你是否理解OO真正的精髓,以上用法展示了面向对象设计的核心思想,通过虚方法调用,实现不同子类对同一行为(方法)的不同实现。希望以下例子可以给大家一些启发:
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2007-03-05 23:05 by
谷钰
public class Employee {
protected String name = "张三";
private double salary = 1000;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public Employee() {
this("王老五", 1);
}
public String getDetails() {
return "姓名:" + this.name + ", 工资: " + this.salary;
}
public double getSalary() {
return this.salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof Employee) {
Employee te = (Employee) o;
return this.salary == te.getSalary() && this.name.equals(te.getName());
}
return false;
}
public int hashCode() {
if (this.name == null) {
return 0;
}
return this.name.hashCode();
}
public String toString() {
return "$$" + this.getDetails();
// return super.toString();
}
public static void printAll(Employee[] all) {
System.out.println("所有员工:");
for (int i = 0; i < all.length; ++i) {
System.out.println(all[i].getDetails());
}
}
public static void main(String[] args) {
Employee e = new Employee("张三", 2500);
System.out.println(e.getDetails());
Manager m = new Manager("李四", 4500, "软件开发部");
System.out.println(m.getDetails());
Employee ee = new Manager("王五", 4500, "软件销售部");
System.out.println(ee.getDetails());
if (ee instanceof Manager) {
Manager mmm = (Manager) ee;
System.out.println(mmm.getDepartment());
}
Employee e2 = new Employee("张三", 2500);
System.out.println(e.equals(e2));
System.out.println(e);
System.out.println("##" + e);
Employee[] eAll = {
e, m, ee
};
printAll(eAll);
}
}
class Manager extends Employee {
private String department = "44";
public Manager() {
super();
this.department = "计算机";
}
public Manager(String name, double salary, String department) {
super(name, salary);
this.department = department;
}
public String getDetails() {
return super.getDetails() + ", 管理部门: " + this.department;
}
public String getDepartment() {
return this.department;
}
}
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2007-03-05 23:11 by
谷钰
核心在
public static void printAll(Employee[] all) {
System.out.println("所有员工:");
for (int i = 0; i < all.length; ++i) {
System.out.println(all[i].getDetails());
}
}
函数的设计上,通过Employee隐藏所有雇员子类的细节,通过getDetails()方法来隐藏不同雇员(Manger,Engineer等)对详细信息的函数细节。
只有这样的函数才能最大程度上复用,既当设计有新的Employee子类定义也不许要对此函数做任何的修改,个人认为面向对象的最大好处是提高程序的复用性,降低维护成本。这些需要多态,继承才能作到。:)
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2007-03-06 09:38 by
大胃
谢谢 谷钰 的回复!
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2008-05-21 17:06 by
tonytang
to 谷钰,你的代码也没有回答tcpipok的疑问啊。子类和父类定义相同的属性有意义吗?
#
re: 你真的理解了继承和多态吗?
回复
更多评论
2008-06-25 11:00 by
shell
写的太好了。
学习了很多。
新用户注册
刷新评论列表
只有注册用户
登录
后才能发表评论。
网站导航:
博客园
IT新闻
知识库
C++博客
博问
管理
相关文章:
IntelliJ IDEA 常用快捷键
[Tips] Windows环境下Apache最基本的调优方法
"上海"是如何变成"涓婃捣"的?
如何让统一版本的Eclipse RCP应用同时支持多个平台
Java命令行实用工具jps和jstat
用Scala解Hanoi塔
[Tips] Spring+Hibernate之“暴力”update
[Tips] Spring 2.5.6新特性之packagesToScan
easyb - Getting Started
Spring 3.0前瞻
Powered by:
BlogJava
Copyright © laogao