`
dandy
  • 浏览: 67267 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

一件私事

    博客分类:
  • java
阅读更多
出自 《java puzzle》


在下面的程序中,子类的一个域具有与超类的一个域相同的名字。那么,这个程序会打印出什么呢?

class Base {
public String className = "Base";
}
class Derived extends Base {
private String className = "Derived";
}
public class PrivateMatter {
public static void main(String[ ] args) {
System.out.println(new Derived().className);
}
}

对该程序的表面分析可能会认为它应该打印Derived,因为这正是存储在每一个Derived实例的className域中的内容。
更深入一点的分析会认为Derived类不能编译,因为Derived中的className变量具有比Base中的className变量更具限制性的访问权限。
如果你尝试着编译该程序,就会发现这种分析也不正确。该程序确实不能编译,但是错误却出在PrivateMatter中。

如果className是一个实例方法,而不是一个实例域,那么Derived.className()将覆写Base.className(),而这样的程序是非法的。一个覆写方法的访问修饰符所提供的访问权限与被覆写方法的访问修饰符所提供的访问权限相比,至少要一样多[JLS 8.4.8.3]。
因为className是一个域,所以Derived.className隐藏(hide)了Base.className,而不是覆盖了它[JLS 8.3]。对一个域来说,当它要隐藏另一个域时,如果隐藏域的访问修饰符提供的访问权限比被隐藏域的少,尽管这么做不可取的,但是它确实是合法的。事实上,对于隐藏域来说,如果它具有与被隐藏域完全无关的类型,也是合法的:即使Derived.className是GregorianCalendar类型的,Derived类也是合法的。
在我们的程序中的编译错误出现在PrivateMatter类试图访问Derived.className的时候。尽管Base有一个公共域className,但是这个域没有被继承到Derived类中,因为它被Derived.className隐藏了。在Derived类内部,域名className引用的是私有域Derived.className。因为这个域被声明为是private的,所以它对于PrivateMatter来说是不可访问的。因此,编译器产生了类似下面这样的一条错误信息:
PrivateMatter.java:11: className has private access in Derived
System.out.println(new Derived().className);
^
请注意,尽管在Derived实例中的公共域Base.className被隐藏了,但是我们还是可以通过将Derived实例转型为Base来访问到它。下面版本的PrivateMatter就可以打印出Base:
public class PrivateMatter {
public static void main(String[] args) {
System.out.println(((Base)new Derived()).className);
}
}
这说明了覆写与隐藏之间的一个非常大的区别。一旦一个方法在子类中被覆写,你就不能在子类的实例上调用它了(除了在子类内部,通过使用super关键字来方法)。然而,你可以通过将子类实例转型为某个超类类型来访问到被隐藏的域,在这个超类中该域未被隐藏。
如果你想让这个程序打印Derived,也就是说,你想展示覆写行为,那么你可以用公共方法来替代公共域。在任何情况下,这都是一个好主意,因为它提供了更好的封装[EJ Item 19]。下面的程序版本就使用了这项技术,并且能够打印出我们所期望的Derived:
class Base {
public String getClassName() {
return "Base";
}
}
class Derived extends Base {
public String getClassName() {
return "Derived";
}
}
public class PrivateMatter {
public static void main(String[] args) {
System.out.println(new Derived().getClassName());
}
}
请注意,我们将Derived类中的getClassName方法声明成了public的,尽管在最初的程序中与其相对应的域是私有的。就像前面提到的那样,覆写方法的访问修饰符与它要覆写的方法的访问修饰符相比,所具有的限制性不能有任何降低。
本谜题的教训是隐藏通常都不是一个好主意。Java语言允许你去隐藏变量、嵌套类型,甚至是静态方法(就像在谜题48所展示的那样),但是你不能认为你就应该去隐藏。隐藏的问题在于它将导致读者头脑的混乱。你正在使用一个被隐藏实体,或者是正在使用一个执行了隐藏的实体吗?要避免这类混乱,只需避免隐藏。
如果一个类要隐藏一个域,而用来隐藏该域的域具有的可访问性比被隐藏域更具限制性,就像我们最初的程序那样,那么这就违反了包容性(subsumption)原则,即大家所熟知的Liskov置换原则(Liskov Substitution Principle)[Liskov87]。这项原则叙述道,你能够对基类所作的任何事,都同样能够作用于其子类。包容性是面向对象编程的自然心理模型的一个不可分割的部分。无论何时,只要违反了这项原则,就会对程序的理解造成困难。还有其它数种用另一个域来隐藏某个域的方法也会违反包容性:例如,两个域具有不同的类型;一个域是静态的而另一个域不是;一个域是final的而另一个域不是;一个域是常量而另一个域不是;以及两个域都是常量但是它们具有不同的值。
对于语言设计者而言,应该考虑消除隐藏的可能性:例如,使所有的域都隐含地是私有的。如果这样做显得过于严苛,那么至少应该考虑对隐藏进行限制,以使其遵守包容性原则。
总之,当你在声明一个域、一个静态方法或一个嵌套类型时,如果其名字与基类中相对应的某个可访问的域、方法或类型相同,就会发生隐藏。隐藏是容易产生混乱的:违反包容性的隐藏域在某种意义上是特别有害的。更一般地讲,除了覆写之外,要避免名字重用。

1
0
分享到:
评论

相关推荐

    Java解惑PPT7

    首先,我们来看Puzzle 66:一件私事。这个谜题涉及到了Java中的继承和成员变量的覆盖(overridden)与隐藏(hidden)。在Java中,方法的覆盖要求子类中的方法至少有与父类相同的访问权限,但成员变量没有这样的限制...

    Java解惑(谜题)CHM中英文双版本

    谜题66:一件私事 谜题67:对字符串上瘾 谜题68:灰色的阴影 谜题69:黑色的渐隐 谜题70:一揽子交易 谜题71:进口税 谜题72:终极危难 谜题73:你的隐私正在公开 谜题74:同一性的危机 谜题75:头还是尾?...

    高考英语词汇表(有中文)

    这是一件私事。” 40. **affect vt. 影响**:动词,表示对事物产生影响或作用。例如,“The weather affected our plans.天气影响了我们的计划。” 41. **afford vt. 负担得起**:动词,表示有足够的资源承担某事...

    如何突破秘书关与前台关.doc

    我有一件紧急且重要的事情需要立即与张总商讨,您能否帮我将电话直接转给他?”这种方式既表达了请求的紧迫性,也展现出了对话者的礼貌和尊重。大多数情况下,秘书或前台人员都不愿意拒绝这样合理且礼貌的要求。 ##...

    十大管理技巧帮你统筹时间.doc

    你需要有一个办法记住这件事,并在未来的某个时间提醒你。 七、保持桌面整洁 我从不相信一个把自己的工作环境弄得乱糟糟的人会是一个优秀的时间管理者。同样的道理,一个人的卧室或是办公室一片狼藉,他也不会是一...

    43种方法简化你的生活.doc

    32. **一次性任务完成**:做事时避免分心,一次只做一件事。 33. **检查钱包**:定期整理钱包,避免丢失重要物品。 34. **专注**:将精力集中在一件事情上,提高专注度。 35. **备用垃圾袋**:在垃圾桶底部放置...

    房地产企业行政管理制度.doc

    第一百五十三至一百五十九条明确了文件的拟稿、核稿、签发、登记、打印、送件、存档等流程。文件的拟稿权责明确,涉及董事会、公司、党内等不同层面的文件分别由相应负责人签发。对于涉密文件,严格遵循保密原则,...

    ESK2009Bulid0515.zip

    现代企业越来越离不开计算机和网络,基本是人手一台计算机,但是计算机和网络的管理成为一大问题,员工经常用计算机来聊天,做私事、打游戏、下载电影、访问色情网站,这样不仅影响工作,而且对公司文化建设产生不好...

    500强企业员工手册_入职离职人事管理制度规范.ppt

    新员工在被正式录用后,需要准备一系列文件,包括公司发出的《录用通知书》、与前雇主解除劳动合同的证明、学历学位证书、职称证书、身份证复印件以及根据不同地区政策所需的其他证件,如深圳户口员工需要的彩色照片...

    行政管理体系文件交接记录.doc

    对于公章的使用,有严格的流程要求,包括公务和私事用途。空白文件或未填写内容的文件不得随意盖章,已盖章文件的原件或复印件需要妥善保存,不能使用的文件要销毁。证照的使用也需经过综合部的审批,并在复印件上...

    一般英文请假条___-条据书信.docx

    - **表达诚挚**:对因请假可能对公司运营带来的影响表示歉意,并承诺尽快处理完私事返回工作岗位。 5. **实例分析**: - 示例1:这是一份学生向老师请假的简单例子,说明了受伤导致无法上学,并明确了请假的天数...

    公司管理章程.pdf

    2. **入职手续**:包括填资料卡、提交履历表、身份证复印件和照片,以及佩戴工号牌。 3. **新人培训**:新人需接受在职教育,了解公司规章制度和部门奖金制度。 4. **离职规定**:员工离职需提前一个月书面申请,未...

    公司考勤与休假管理制度.doc

    第十四条员工因私事需请假的,可申请事假,事假需提前申请,得到直属上级及人力资源部门批准后方可休假。第十五条员工结婚可申请婚假,需提前提交结婚证复印件进行申请。第十六条女性员工生育可享受产假,具体天数...

    货品进厂联络单格式.doc

    【进厂事由】列出了多种可能的来访目的,如交货、洽谈、参观、包工、提运货物、公事拜访、私事拜访和其他,根据事由,企业可以预先准备相关资料,安排适当的会议或活动。 【厂商自备工具、物品入厂】这一项关注的是...

    XX事业单位请假条格式有些.doc

    - 阐述请假期间的计划,如休息、处理私事,或者如例子中所述“以更好的精力或状态去完成接下来的工作或学习”。 6. **请求批准**: - 在请假条的结尾,要明确提出希望得到批准的意愿,并表示感谢。 7. **签名和...

    大学缓考申请书3篇.docx

    - 包括不同类型的申请书示例,如篇一至篇六所示,分别展示了个人因私事、疾病、参与特殊活动等原因申请缓考的格式。 总之,大学缓考申请是一个严谨的过程,需要学生准确无误地提供信息,并严格按照学校规定操作。...

    公司通讯事务处理规定.doc

    《公司通讯事务处理规定》是企业内部的一种管理制度,旨在规范公司内部的通讯行为,确保通讯工作的有效性和安全性。这份规定涵盖了多个方面的内容,包括通讯设备的管理、使用注意事项、私用禁止、责任分配、外部公关...

    教师年终述职报告合集五篇.docx

    1. **教师职业道德**:报告中提到了教师用欣赏的眼光看待每个人,以宽容的态度对待每件事,这体现了教师高尚的职业道德,尊重和关心每一个学生。 2. **教学质量与责任感**:教师强调了对工作的认真态度,没有因私事...

    电脑维修公司员工管理手册.doc

    5. **奖惩制度**:公司规定了严格的考勤制度,如迟到、早退和工作期间做私事将受到罚款。同时,公司会通过客户回访评估员工表现,优秀的技术服务和满意度将得到奖励。 这份手册强调了员工的专业形象、服务态度以及...

    某药业有限公司人事管理制度.doc

    - 新员工报到需完成一系列手续,包括填写表格、提供证件复印件、体检证明等,入职前需接受岗前培训。 - 试用期满后,用人单位和人事部将评估员工表现,决定是否录用。试用期长短根据劳动合同的期限设定,并包含在...

Global site tag (gtag.js) - Google Analytics