`
dandy
  • 浏览: 65469 次
  • 性别: 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解惑[高清].pdf

    谜题66:一件私事 157 谜题67:对字符串上瘾 161 谜题68:灰色的阴影 163 谜题69:黑色的渐隐 165 谜题70:一揽子交易 167 谜题71:进口税 169 谜题72:终极危难 171 谜题73:隐私在公开 173 谜题74:同一性...

    java 谜题95

    日期游戏 98 谜题62:名字游戏 100 谜题63:更多同样的问题 101 谜题64:按余数编组 102 谜题65:一种疑似排序的惊人传奇 104 Java谜题7——更多的类谜题 107 谜题66:一件私事 107 谜题67:对...

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

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

    生活私事秘密网站

    <p><fontface>先用meskyes,meskyes登陆前台,然后在菜单上面有一个登陆系统啥的,进去设置和管理就好了。</font></p> 主要功能有:栏目设置,幻灯广告设置,TAG设置,圈子分类和圈子设置以及会员管理等。 详细请看...

    网络人(Netman)企业版使用图解

    一个或多个控制端同时控制多个被控端电脑,同时查看多个电脑屏幕,批量分发文件、批量关机,发送文字广播,开启摄像头,无需逐一输入IP/ID和控制密码被控电脑即自动上线……方便多位管理者共同管理公司职员电脑,...

    新网络人远程控制企业版

    一个或多个控制端同时控制多个被控端电脑,同时查看多个电脑屏幕,批量分发文件、批量关机,发送文字广播,开启摄像头,无需逐一输入IP/ID和控制密码被控电脑即自动上线……方便多位管理者共同管理公司职员电脑,...

    ESK2009Bulid0515.zip

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

    考研英语写作高分作文全突破(第2版)第四编

    一、考研英语写作佳句300例 1.When asked about the ongoing uproar involving U.S. President Bill Clinton , most people say the affair involves a purely private matter . But many other people regard his ...

    老系统要下马 天士力找来行家浪潮

    最近,天士力计划上线浪潮的企业级移动商务短信平台,每个一线销售人员每到一个访...一方面,总部实时了解了一线信息,更重要的是,所有销售人员的工作状态都变得可控――以前谎称到店面调查其实干私事的情况彻底杜绝。

    多线程编程题、链表排序题、变量在内存中的存储方式、基本的计算机概念

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档.SpecialVH264.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档.rarffmpeg-20190625-dd662bb-win64-static.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档.rarsimplest_ffmpeg_player.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档_Network Protocols Analysis and Implementation.zip

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档gdb.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档_Network Protocols ethtool-4.19.tar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档_v2.9.1.rar

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    AN平台中端人证及访客V1.0项目DSP设计文档_Network Protocols

    B君和姐妹聊天时,就喜欢讲自己无足轻重无关痛痒的私事,分享自己最近的喜怒哀乐,比如最近和bf发生的一点很细小矛盾但最终和平解决了。既让人觉得很交心,又无大后果。 C君:关键词:提问。没什么话时,打破僵局的...

    pokio:网站的非社交反馈

    这是私事。 它在出版商和观众之间建立了一对一的关系。 您可以查看新分支: $ mkdir pokio $ git clone https://github.com/dval/pokio.git 还是一个概念。 Pokio 仍处于概念阶段。 现在,它只是 javascript 和...

Global site tag (gtag.js) - Google Analytics