今天周六,闲着蛋疼就报名参加了公司的一个java比赛,比赛地点某某大厦11楼会议室,想象中应该是能容纳上百人的超大会议室。没成想,到地方一看,只是一个
能容纳六七人的有圆形会议桌的小会议室。不过这仍然不能熄灭BZ因对Java热爱而燃起的满腔激情,于是满怀热情地投入到了比赛答题中。
一般这样的开头都会给人一种欲抑先扬的感觉,BZ这次当然也不例外...刚开始没做几题,就被其中的一个小题目给绊倒了,题目大体是这样的:
有两个类,一个叫BaseHole,如下所示:
public class BaseHole {
public int i = 1;
public BaseHole () {
bh();
}
public void bh () {
System.out.println("Base Hole - bh()");
}
}
另一个类继承了上面的BaseHole,如下所示:
public class UpConstrutorHole extends BaseHole{
public int i = 2;
public void bh () {
System.out.println("UpConstrutorHole - bh()");
}
public void uch () {
System.out.println("UpConstrutorHole - uch()");
}
}
然后运行如下代码:
public class UpConstructorClient {
public static void main(String[] args) {
BaseHole b = new UpConstrutorHole();// 第8行
System.out.println(b.i);// 第9行
        UpConstrutorHole u = (UpConstrutorHole) b;
        u.uch();// 第11行
u.bh();// 第12行
}
}
问8/9/11/12各行代码分别输出的结果是什么:
A.Base Hole - bh()
1
UpConstrutorHole - uch()
UpConstrutorHole - bh()
B.由于向上造型后b中没有uch()方法,所以第10行给b强转类型后仍然没有uch()方法,故第11行编译报错无法执行
C.Base Hole - bh()
2
UpConstrutorHole - uch()
UpConstrutorHole - bh()
D.UpConstrutorHole - bh()
2
UpConstrutorHole - uch()
UpConstrutorHole - bh()
E.UpConstrutorHole - bh()
1
UpConstrutorHole - uch()
UpConstrutorHole - bh()
本着诚实守信的原则,通过分析上题看看自己是否真正的深刻了解向上造型,务必要先在心里想好自己的答案再往下看。 对于向上造型,我之前知道的点基本就是以下两点:
1、向上造型后的对象,能引用的方法为:如果子类的方法满足重写父类方法的要求,则引用子类的方法,否则引的是父类的方法,毕竟对象的类型是父类类型;
2、向上造型,子类的属性不能覆盖父类。
通过以上两点,可知第9行是1,第12行是UpConstrutorHole - bh(),排除CD,还剩ABE,下面才是本题的重难点。
剩余的ABE总共涉及到两部分内容:
第一部分是B中的强制类型转换,同一个引用,为什么前者没有uch方法,而类型转换之后就有了呢?(所以B是不对的,仿佛是 在用貌似合理的话胡说八道,但是如果强制类型转换原理了解不清楚,很容易就被忽悠了,BZ就是很悲催的踩入了坑里 -- FK) 首先第8行那里进行向上造型,
new了一个UpConstrutorHole对象,就是说在堆内存中真真切切的生成了一个UpConstrutorHole对象,对象的实体数据中存放的就是这个类中的代码,这一点是
确定无疑的;其次,为什么把UpConstrutorHole对象赋值给b引用后就访问不到uch了呢?其实就是BaseHole类型的引用是有可见范围的,该可见范围
包括b中已有的方法属性跟被UpConstrutorHole类重写的方法,而UpConstrutorHole中的其余方法对该引用不可见,所以形成了向上造型的这种访问形式;
第三,为什么强制类型转换后就又能访问uch方法了呢?还是这个引用指针捣的鬼,强制类型转换后,引用的可见范围被改变,变为可以访问到UpConstrutorHole
类中的方法,所以又能引用到uch方法,虽然对象没变,引用地址没变,但是只要引用的类型变了其访问范围也会改变。至此,B的迷雾已经被拨开,pass掉。
第二部分,运行程序可知第8行输出的是UpConstrutorHole类中的bh方法打印的字符,为什么父类的构造器中执行的也是子类中重写的方法呢?其实这就要
追溯到对象初始化的时候的执行顺序了,翻阅了一下"圣经" - 《Thinking In Java》,发现有相关讲解,大意如下:
构造器初始化的顺序:
1、先将分配给对象的存储空间初始化为二进制的0;
2、在子类构造器执行前,先调用基类的构造器,此时如果基类的构造器中有子类重写的方法,会调用子类中的方法;
3、按顺序调用成员变量的初始化方法;
4、调用子类的构造器
而且后面还特意加了一句嘱咐:编写构造器时,尽可能的避免调用其他方法,尤其是非final跟private的方法。不然就可能出现如上题所示的莫名现象。
经此一役,发觉要学的东西仍然浩如烟海。还是那句话,学习之路,一定要多给自己灌鸡汤,Never at rest!
												

向上造型中让我入坑的地方 (><)的更多相关文章

  1. 小程序入坑(一)---如何引入iconfont 字体图标

    最近一直忙于日常任务,其实是懒癌又犯了..........不过因为自己的“懒癌”,“不思进取”给自己挖了不少坑. 一,小程序工具的安装 打开简易小程序的官网https://mp.weixin.qq.c ...

  2. Java中的向上造型和向下造型等

    package com.study.oop.day01; /**  * 如果某个方法是静态 的,它的行为就不具有多态性  * @author LuHongGang  * @date 2017年6月5日 ...

  3. python函数中把列表(list)当参数时的"入坑"与"出坑"

    在Python函数中,传递的参数如果默认有一个为 列表(list),那么就要注意了,此处有坑!! 入坑 def f(x,li=[]): for i in range(x): li.append(i*i ...

  4. 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程

    反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑)   背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...

  5. eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南

    eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...

  6. RoboGuice 3.0 (一)入坑篇

    RoboGuice是什么? 一个Android上的依赖注入框架. 依赖注入是什么? 从字面理解,这个框架做了两件事情,第一是去除依赖,第二是注入依赖.简单理解就是,将对象的初始化委托给一个容器控制器, ...

  7. [SSIS] 在脚本里面使用数据库连接字符串进行查询等处理, 入坑

    入坑.!!!!! SSIS 中dts包 设置的  ADO.Net连接, 在传入脚本的时候, 我要使用 数据库连接,进行数据的删除操作. 于是我使用了 了如下的 代码 使用的是windows 身份验证, ...

  8. webpack入坑之旅(六)配合vue-router实现SPA

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

  9. webpack入坑之旅(五)加载vue单文件组件

    这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...

随机推荐

  1. JPA的初级CRUD-01

    一.JPA 1.1 什么是JPA JPA:(Java Persistence API) ORM的规范 JPA是规范,Hibernate是它的实现(不唯一,但最好) 最底层的操作还是JDBC(引入驱动包 ...

  2. function()

    avaScript中的function可以有以下两种用法:一是做“普通逻辑代码容器”,也就是我们通常意义上的函数.方法,和我们C/C++里的函数没什么大分别,只是写法稍有不同.用法更加灵活:二是做对象 ...

  3. 你可能不知道的web api

    简介 作为前端工作者,我们的工作与web是分不开的,随着HTML5的日益壮大,浏览器自带的webapi也随着增多.本篇文章主要选取了几个有趣且有用的webapi进行介绍,分别介绍其用法.用处以及浏览器 ...

  4. ext__给grid Panel设置绑定事件

    使用面板来展示详情信息 1.创建一个面板 (双击添加) 2.给该面板设置itemid的值为:detailPanel 3.给面板设置模板 4.添加下面的内容 id:{id}</br> nam ...

  5. nodejs多版本管理

    nvm安装步骤: Windows版本安装 https://github.com/coreybutler/nvm-windows/releases 下载最新的setup文件 ,解压缩,安装到C:\Dev ...

  6. 28.TreeSet

    与HashSet是基于HashMap实现一样,TreeSet同样是基于TreeMap实现的.在前一篇中详细讲解了TreeMap实现机制,如果客官详细看了这篇博文或者对TreeMap有比较详细的了解,那 ...

  7. autium designer smart pdf一个小问题

    今天在使用ad的smart  pdf时遇到一个小问题  就是 使用的是AD17,生成PDF,PDF没有把芯片的引脚标号显示出来(还有其它的芯片也是一样的,但是奇怪的是:只有在原理图元器件右边的没有显示 ...

  8. Android中弹出dialog后无法捕捉back键

    一.需求 在Android开发过程中,弹出dialog后无法捕捉back键,点击back按键无响应. 二.解决方案 原因:弹出dialog后,activity失去焦点,dialog获得当前焦点. 解决 ...

  9. linux下tomcat服务器的相关命令

    一:Linux下tomcat服务的启动.关闭与错误跟踪,使用PuTTy远程连接到服务器以后,通常通过以下几种方式启动关闭tomcat服务:切换到tomcat主目录下的bin目录(cd usr/loca ...

  10. 解决jenkins控制台中文乱码问题

    1,进入[系统管理]->[系统设置]->全局属性:KEY: LANG; VALUE:zh.CH.UTF-8 2,修改Jenkins.xml文件 在Jenkins安装目录下找到jenkins ...