以前有个java游戏叫地底墓穴探秘北京阿姨大学什么的,有谁知道吗?

Java I/O底层是如何工作的? - ImportNew
本博文主要讨论I/O在底层是如何工作的。本文服务的读者,迫切希望了解操作是在机器层面如何进行映射,以及应用运行时硬件都做了什么。假定你熟悉基本的I/O操作,比如通过Java I/O API读写文件。这些内容不在本文的讨论范围。
缓存处理和内核vs用户空间
缓冲与缓冲的处理方式,是所有I/O操作的基础。术语“输入、输出”只对数据移入和移出缓存有意义。任何时候都要把它记在心中。通常,进程执行操作系统的I/O请求包括数据从缓冲区排出(写操作)和数据填充缓冲区(读操作)。这就是I/O的整体概念。在操作系统内部执行这些传输操作的机制可以非常复杂,但从概念上讲非常简单。我们将在文中用一小部分来讨论它。
上图显示了一个简化的“逻辑”图,它表示块数据如何从外部源,例如一个磁盘,移动到进程的存储区域(例如RAM)中。首先,进程要求其缓冲通过read()系统调用填满。这个系统调用导致内核向磁盘控 制硬件发出一条命令要从磁盘获取数据。磁盘控制器通过直接将数据写入内核的内存缓冲区,不需要主CPU进一步帮助。当请求read()操作时,一旦磁盘控制器完成了缓存的填 写,内核从内核空间的临时缓存拷贝数据到进程指定的缓存中。
有一点需要注意,在内核试图缓存及预取数据时,内核空间中进程请求的数据可能已经就绪了。如果这样,进程请求的数据会被拷贝出来。如果数据不可用,则进程被挂起。内核将把数据读入内存。
你可能已经多次听说过虚拟内存了。让我再介绍一下。
所有都使用虚拟内存。虚拟内存意味着人工或者虚拟地址代替物理(硬件RAM)内存地址。虚拟地址有两个重要优势:
多个虚拟地址可以映射到相同的物理地址。
一个虚拟地址空间可以大于实际可用硬件内存。
在上面介绍中,从内核空间拷贝到最终用户缓存看起来增加了额外的工作。为什么不告诉磁盘控制器直接发送数据到用户空间的缓存呢?好吧,这是由虚拟内存实现的。用到了上面的优势1。
通过将内核空间地址映射到相同的物理地址作为一个用户空间的虚拟地址,DMA硬件(只能访问物理内存地址)可以填充缓存。这个缓存同时对内核和用户空间进程可见。
这就消除了内核和用户空间之间的拷贝,但是需要内核和用户缓冲区使用相同的页面对齐方式。缓冲区必须使用的块大小的倍数磁盘控制器(通常是512字节的磁盘扇区)。操作系统将其内存地址空间划分为页面,这是固定大小的字节组。这些内存页总是磁盘块大小的倍数和通常为2倍(简化寻址)。典型的内存页面大小是和4096字节。虚拟和物理内存页面大小总是相同的。
为了支持虚拟内存的第2个优势(拥有大于物理内 存的可寻址空间)需要进行虚拟内存分页(通常称为页交换)。这种机制凭借虚拟内存空间的页可以持久保存在外部磁盘存储,从而为其他虚拟页放入物理内存提供了空间。本质上讲,物理内存担当了分页区域的缓存。分页区是磁盘上的空间,内存页的内容被强迫交换出物理内存时会保存到这里。
调整内存页面大小为磁盘块大小的倍数,让内核可以直接发送指令到磁盘控制器硬件,将内存页写到磁盘或者在需要时重新加载。事实证明,所有的磁盘I/O操作都是在页面级别上完成的。这是数据在现代分页操作系统上在磁盘与物理内存之间移动的唯一方式。
现代CPU包含一个名为的子系统。这 个设备逻辑上位于CPU与物理内存之间。它包含从虚拟地址向物理内存地址转化的映射信息。当CPU引用一个内存位置时,MMU决定哪些页需要驻留(通常通过移位或屏蔽地址的某些位)以及转化虚拟页号到物理页号(由硬件实现,速度奇快)。
面向文件、块I/O
文件I/O总是发生在文件系统的上下文切换中。文件系统跟磁盘是完全不同的事物。磁盘按段存储数据,每段512字节。它是硬件设备,对保存的文件语义一无所知。它们只是提供了一定数量的可以保存数据的插槽。从这方面来说,一个磁盘的段与 内存分页类似。它们都有统一的大小并且是个可寻址的大数组。
另一方面,文件系统是更高层抽象。文件系统是安排和翻译保存磁盘(或其它可随机访问,面向块的设备)数据的一种特殊方法。你写的代码几乎总是与文件系统交互,而不与磁盘直接交互。文件系统定义了文件名、路径、文件、文件属性等抽象。
一个文件系统组织(在硬盘中)了一系列均匀大小的数据块。有些块保存元信息,如空闲块的映射、目录、索引等。其它块包含实际的文件数据。单个文件的元信息描述哪些块包含文件数据、数据结束位置、最后更新时间等。当用户进程发送请求来读取文件数据时,文件系统实现准确定位数据在磁盘上的位置。然后采取行动将这些磁盘扇区放入内存中。
文件系统也有页的概念,它的大小可能与一个基本内存页面大小相同或者是它的倍数。典型的文件系统页面大小范围从字节,并且总是一个基本内存页面大小的倍数。
分页文件系统执行I/O可以归结为以下逻辑步骤:
确定请求跨越了哪些文件系统分页(磁盘段的集合)。磁盘上的文件内容及元数据可能分布在多个文件系统页面上,这些页面可能是不连续的。
分配足够多的内核空间内存页面来保存相同的文件系统页面。
建立这些内存分页与磁盘上文件系统分页的映射。
对每一个内存分页产生分页错误。
虚拟内存系统陷入分页错误并且调度pagins(页面调入),通过从磁盘读取内容来验证这些页面。
一旦pageins完成,文件系统分解原始数据来提取请求的文件内容或属性信息。
需要注意的是,这个文件系统数据将像其它内存页一样被缓存起来。在随后的I/O请求中,一些数据或所有文件数据仍然保存在物理内存中,可以直接重用不需要从磁盘重读。
文件加锁是一种机制,一个进程可以阻止其它进程访问一个文件或限制其它进程访问该文件。虽然名为“文件锁定”,意味着锁定整个文件(经常做的)。锁定通常可以在一个更细粒度的水平。随着粒度下降到字节级,文件的区域通常会被锁定。锁与特定文件相关联,起始于文件的指定字节位置并运行到指定的字节范围。这一点很重要,因为它允许多个进程协作访问文件的特定区域而不妨碍别的进程在文件其它位置操作。
文件锁有两种形式:共享和独占。多个共享锁可以同时在相同的文件区域有效。另一方面,独占锁要求没有其它锁对请求的区域有效。
并非所有的I/O是面向块的。还有流I/O,它是管道的原型,必须顺序访问I/O数据流的字节。常见的数据流有TTY(控制台)设备、打印端口和网络连接。
数据流通常但不一定比块设备慢,提供间歇性输入。大多数操作系统允许在非阻塞模式下工作。允许一个进程检查数据流的输入是否可用,不必在不可用时发生阻塞。这种管理允许进程在输入到达时进行处理,在输入流空闲时可以执行其他功能。
比非阻塞模式更进一步的是有条件的选择(readiness selection)。它类似于非阻塞模式(并且通常建立在非阻塞模式基础上),但是减轻了操作系统检查流是否就绪准的负担。操作系统可以被告知观察流集合,并向进程返回哪个流准备好的指令。这种能力允许进程通过利用操作系统返回 的准备信息,使用通用代码和单个线程复用多个活动流。这种方式被广泛用于网络服务器,以便处理大量的网络连接。准备选择对于大容量扩展是至关重要的。
到此为止,对这个非常复杂的话题有一大堆技术术语。
如果你有想法和疑问,请给给我发评论。
学习快乐!!
原文链接:
- 译文链接: [ 转载请保留原文出处、译者和译文链接。]
关于作者:
(新浪微博:)
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:ImportNew.
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2018 ImportNew热门搜索:
当前位置:&&&&&&《无终仙境》古墓探秘
粽子节讲“粽子”
《无终仙境》古墓探秘
粽子节讲“粽子”
时间:作者:游戏厂商来源:小皮网
  临近端午,各种口味的粽子都纷纷上架。而在我们不曾知晓的另一个世界,各种&粽子&也开始活动了&&端午粽飘香,粽子节咱们来说说盗墓界的&粽子&纪实!
  当然啦,由于墓中的&粽子&太过惊悚,咱还是先看看养眼的粽子:
  《无终仙境》端午粽飘香(图片来源于网络)
  &粽子&?什么是&粽子&
  粽子是一句在盗墓者中流传的暗语,指墓里保存的比较完好,没有腐烂但已经尸变的尸体,摸到大粽子就是碰上麻烦了,指僵尸、恶鬼之类不干净的东西。
  电影寻龙诀中的&粽子&
  &粽子&这个概念最早出现在天下霸唱的《鬼吹灯》小说中。摸金校尉胡八一,王胖子在地下墓穴寻宝时,遇上风水较为奇特,或者墓中环境发生变化,又或是死者本身怨气过大,尸体就会发生一系列的尸变,盗墓者们称之为&粽子&。由于下墓着忌讳&死&&尸&等带有晦气的词汇,所以干脆就用&粽子&来代表墓中的尸骨。
  &粽子&也分多种,根据外表可分为八种:
  1.大粽子:厉害的僵尸、恶鬼之类的东西。
  2.老粽子:可发生尸变的不好对付的僵尸。
  3.干粽子:是指墓里的尸体烂得只剩下一堆白骨了。
  4.肉粽子:是指尸体身上值钱的东西多。
  5.血粽子:血尸墓中的粽子,最厉害。
  6.霉粽子:是指具有尸毒的尸体。
  7.女粽子:女尸尸化后的粽子,比普通粽子更厉害
  8.小粽子:儿童尸体尸化后的粽子。
  电视剧盗墓笔记中的女粽子
  在天下霸唱《鬼吹灯》系列电影《寻龙诀》中,片头的那位棺木中千年不腐的西夏公主就是典型的&女粽子&。由于外形美貌,也算是给&粽子&们提升了不少颜值。
  《无终仙境》中也出现过不少&粽子&,印象最深刻的当属引发二哥之死的&千年妖胎&&&小粽子。
  关于这个小粽子,文中是这样描写的:
  棺中应是个身怀六甲的妇人,死后埋到此处已久,坟头都没了,尸身也几乎成了枯骨,但那死孩子却不似成形的胎儿。他心下一怔,记起祖师爷说过的话,旧时有一路炼气的旁门左道,多为一师一徒。师父死后,徒弟将师父脐下三寸剜下,道门儿中说这是丹田,要将这块肉给身怀六甲的妇人吃下去,等这个妇人再生下来的孩子,打一落地便有道行,民间俗话说是&胎里道&。
  尘世中肉身易朽,用这法子换肉身,待有千年道行便可长生不死。
  五株槐树当中的棺材,里面是个身怀&胎里道&的妇人,临盆之前死了。棺材埋在坟中,腹中妖胎挣扎出来,却也困死在棺材之中,可见犯了天忌,天意必然不佑。
  崔老道收敛了死孩子的肉身,到底是千年成形的妖胎,已不知转过多少次肉身。他听说&千年妖胎&可以辟邪挡灾,便带到余家大坟破庙之中,用香火供养起来。
  可见这千年妖胎成型的小粽子也不是容易对付的家伙&&而几十年后,挖出这个死孩子的二哥一夜猝死,更是验证了小粽子的诡异。
  《无终仙境》中出现的第二个&粽子&是一只女粽子,明朝年间跳入枯井身亡,百年尸身不腐,仍保持着死前的容颜。后来我们得知这只女粽子是因为吞噬了&仙虫&才得以尸身不腐,当&仙虫&被三姥姥取出后,便瞬间化为白骨。
  电影寻龙诀中的AB粽子造型
  《无终仙境》中还出现了一只打酱油的僵尸&粽子&&&伏虎庄的大庄主。崔老道作法时恰巧遇上天外阵雷,一只狸猫惊得掉下来,正巧掉在&死&去的大庄主脸上。大庄主猛然睁开眼,翻白的眼珠子转了过来,一人一猫脸对脸、眼对眼,借尸还魂变成了僵尸鬼。崔老道追尸一夜,才在黎明时分太阳升起时制服了这只刚刚尸变的&粽子&。
  写到这里,小编感觉今年的端午节已经吃不消各种馅儿的粽子了&&满脑子都是各种恐怖的古墓&粽子&,叫我如何能安心下口正常的粽子哇!还是就此打住吧。
  《无终仙境》游戏截图
  手游《无终仙境》由天下霸唱亲任剧情策划,力求为众位读者玩家们展现出原汁原味的霸唱风格,更有专属定制的游戏剧情!迷宫幻境,地底深渊,戎人古坟中掩藏千年的宝藏,埋藏在时间洪流中的西周秘宝,一切等待玩家们前来探索!
评论(0条评论)
类&&&型:角色扮演
评&&&分:分
XiaoPi.Com 小皮游戏网 All Rights Reserved.闽ICP备号-1
厦门小皮网络有限公司
联系电话:
文网文[8号谈谈对Java多态性的一点理解
转载 & & 作者:Angel_Kitty
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定
面向对象编程有三大特性:封装、继承、多态。
&&&&& 封装隐藏了类的内部实现机制,可以在不影响使用的情况下改变类的内部结构,同时也保护了数据。对外界而已它的内部细节是隐藏的,暴露给外界的只是它的访问方法。
&&&&& 继承是为了重用父类代码。两个类若存在IS-A的关系就可以使用继承。,同时继承也为实现多态做了铺垫。那么什么是多态呢?多态的实现机制又是什么?请看我一一为你揭开:
&&&&& 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
&&&&& 比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
&&&&& 酒 a = 剑南春
&&&&& 酒 b = 五粮液
&&&&& 酒 c = 酒鬼酒
&&&&& 这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
&&&&& 诚然,要理解多态我们就必须要明白什么是“向上转型”。在继承中我们简单介绍了向上转型,这里就在啰嗦下:在上面的喝酒例子中,酒(Win)是父类,剑南春(JNC)、五粮液(WLY)、酒鬼酒(JGJ)是子类。我们定义如下代码:
JNC a = new JNC();
&&&&& 对于这个代码我们非常容易理解无非就是实例化了一个剑南春的对象嘛!但是这样呢?&&
Wine a = new JNC();
&&&&& 在这里我们这样理解,这里定义了一个Wine 类型的a,它指向JNC对象实例。由于JNC是继承与Wine,所以JNC可以自动向上转型为Wine,所以a是可以指向JNC实例对象的。这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。
&&&&& 但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了---1&&&&
public class Wine {
public void fun1(){
System.out.println("Wine 的Fun.....");
public void fun2(){
System.out.println("Wine 的Fun2...");
public class JNC extends Wine{
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
public void fun1(String a){
System.out.println("JNC 的 Fun1...");
* 子类重写父类方法
* 指向子类的父类引用调用fun2时,必定是调用该方法
public void fun2(){
System.out.println("JNC 的Fun2...");
public class Test {
public static void main(String[] args) {
Wine a = new JNC();
-------------------------------------------------
Wine 的Fun.....
JNC 的Fun2...
从程序的运行结果中我们发现,a.fun1()首先是运行父类Wine中的fun1().然后再运行子类JNC中的fun2()。
&&&&& 分析:在这个程序中子类JNC重载了父类Wine的方法fun1(),重写fun2(),而且重载后的fun1(String a)与 fun1()不是同一个方法,由于父类中没有该方法,向上转型后会丢失该方法,所以执行JNC的Wine类型引用是不能引用fun1(String a)方法。而子类JNC重写了fun2() ,那么指向JNC的Wine引用会调用JNC中fun2()方法。
&&&&& 所以对于多态我们可以总结如下:
&&&&& 指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
&&&&& 对于面向对象而已,多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。
多态的实现
&&&&& 2.1实现条件
&&&&& 在刚刚开始就提到了继承在为多态的实现做了准备。子类Child继承父类Father,我们可以编写一个指向子类的父类类型引用,该引用既可以处理父类Father对象,也可以处理子类Child对象,当相同的消息发送给子类或者父类对象时,该对象就会根据自己所属的引用而执行不同的行为,这就是多态。即多态性就是相同的消息使得不同的类做出不同的响应。
&&&&& Java实现多态有三个必要条件:继承、重写、向上转型。
&&&&&&&& 继承:在多态中必须存在有继承关系的子类和父类。
&&&&&&&& 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
&&&&&&&& 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
&&&&&&&& 只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
&&&&& 对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
&&&&& 2.2实现形式
&&&&& 在Java中有两种形式可以实现多态。继承和接口。
&&&&& 2.2.1、基于继承实现的多态
&&&&& 基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。&&&&&
public class Wine {
public String getName() {
public void setName(String name) {
this.name =
public Wine(){
public String drink(){
return "喝的是 " + getName();
* 重写toString()
public String toString(){
public class JNC extends Wine{
public JNC(){
setName("JNC");
* 重写父类方法,实现多态
public String drink(){
return "喝的是 " + getName();
* 重写toString()
public String toString(){
return "Wine : " + getName();
public class JGJ extends Wine{
public JGJ(){
setName("JGJ");
* 重写父类方法,实现多态
public String drink(){
return "喝的是 " + getName();
* 重写toString()
public String toString(){
return "Wine : " + getName();
public class Test {
public static void main(String[] args) {
//定义父类数组
Wine[] wines = new Wine[2];
//定义两个子类
JNC jnc = new JNC();
JGJ jgj = new JGJ();
//父类引用子类对象
wines[0] =
wines[1] =
for(int i = 0 ; i & 2 ; i++){
System.out.println(wines[i].toString() + "--" + wines[i].drink());
System.out.println("-------------------------------");
Wine : JNC--喝的是 JNC
Wine : JGJ--喝的是 JGJ
-------------------------------
在上面的代码中JNC、JGJ继承Wine,并且重写了drink()、toString()方法,程序运行结果是调用子类中方法,输出JNC、JGJ的名称,这就是多态的表现。不同的对象可以执行相同的行为,但是他们都需要通过自己的实现方式来执行,这就要得益于向上转型了。
&&&&& 我们都知道所有的类都继承自超类Object,toString()方法也是Object中方法,当我们这样写时:
Object o = new JGJ();
System.out.println(o.toString());
&&&& 输出的结果是Wine : JGJ。
&&&&& Object、Wine、JGJ三者继承链关系是:JGJ—&Wine—&Object。所以我们可以这样说:当子类重写父类的方法被调用时,只有对象继承链中的最末端的方法才会被调用。但是注意如果这样写:
Object o = new Wine();
System.out.println(o.toString());
输出的结果应该是Null,因为JGJ并不存在于该对象继承链中。
&&&&& 所以基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。
&&&&& 如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。
&&&&& 2.2.2、基于接口实现的多态
&&&&& 继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。
&&&&& 在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。
&&&&& 继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。
三、经典实例。
&&&&& 通过上面的讲述,可以说是对多态有了一定的了解。现在趁热打铁,看一个实例。该实例是有关多态的经典例子
public class A {
public String show(D obj) {
return ("A and D");
public String show(A obj) {
return ("A and A");
public class B extends A{
public String show(B obj){
return ("B and B");
public String show(A obj){
return ("B and A");
public class C extends B{
public class D extends B{
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
运行结果:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
&&&&& 在这里看结果1、2、3还好理解,从4开始就开始糊涂了,对于4来说为什么输出不是“B and B”呢?
&&&&& 首先我们先看一句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。这句话对多态进行了一个概括。其实在继承链中对象方法的调用存在一个优先级:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
&&&&& 分析:
&&&& 从上面的程序中我们可以看出A、B、C、D存在如下关系。
&&&&& 首先我们分析5,a2.show(c),a2是A类型的引用变量,所以this就代表了A,a2.show(c),它在A类中找发现没有找到,于是到A的超类中找(super),由于A没有超类(Object除外),所以跳到第三级,也就是this.show((super)O),C的超类有B、A,所以(super)O为B、A,this同样是A,这里在A中找到了show(A obj),同时由于a2是B类的一个引用且B类重写了show(A obj),因此最终会调用子类B类的show(A obj)方法,结果也就是B and A。
&&&&& 按照同样的方法我也可以确认其他的答案。
&&&&& 方法已经找到了但是我们这里还是存在一点疑问,我们还是来看这句话:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。这我们用一个例子来说明这句话所代表的含义:a2.show(b);
&&&&& 这里a2是引用变量,为A类型,它引用的是B对象,因此按照上面那句话的意思是说有B来决定调用谁的方法,所以a2.show(b)应该要调用B中的show(B obj),产生的结果应该是“B and B”,但是为什么会与前面的运行结果产生差异呢?这里我们忽略了后面那句话“但是这儿被调用的方法必须是在超类中定义过的”,那么show(B obj)在A类中存在吗?根本就不存在!所以这句话在这里不适用?那么难道是这句话错误了?非也!其实这句话还隐含这这句话:它仍然要按照继承链中调用方法的优先级来确认。所以它才会在A类中找到show(A obj),同时由于B重写了该方法所以才会调用B类中的方法,否则就会调用A类中的方法。
&&&&& 所以多态机制遵循的原则概括为:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法,但是它仍然要根据继承链中方法调用的优先级来确认方法,该优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。
以上所述是小编给大家介绍的Java多态性的一点理解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具}

我要回帖

更多关于 探秘时刻 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信