向上造型中让我入坑的地方 (><)
今天周六,闲着蛋疼就报名参加了公司的一个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!
向上造型中让我入坑的地方 (><)的更多相关文章
- 小程序入坑(一)---如何引入iconfont 字体图标
最近一直忙于日常任务,其实是懒癌又犯了..........不过因为自己的“懒癌”,“不思进取”给自己挖了不少坑. 一,小程序工具的安装 打开简易小程序的官网https://mp.weixin.qq.c ...
- Java中的向上造型和向下造型等
package com.study.oop.day01; /** * 如果某个方法是静态 的,它的行为就不具有多态性 * @author LuHongGang * @date 2017年6月5日 ...
- python函数中把列表(list)当参数时的"入坑"与"出坑"
在Python函数中,传递的参数如果默认有一个为 列表(list),那么就要注意了,此处有坑!! 入坑 def f(x,li=[]): for i in range(x): li.append(i*i ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- eclipse中导入外部包却无法查看对应源码或Javadoc的入坑指南
eclipse中导入外部包却无法查看对应源码或Javadoc的 入坑指南 出现这个错误的原因是,你虽然导入了.jar包,但没有配置对应的Javadoc或源码路径,所以在编辑器中无法查看源 码和对应AP ...
- RoboGuice 3.0 (一)入坑篇
RoboGuice是什么? 一个Android上的依赖注入框架. 依赖注入是什么? 从字面理解,这个框架做了两件事情,第一是去除依赖,第二是注入依赖.简单理解就是,将对象的初始化委托给一个容器控制器, ...
- [SSIS] 在脚本里面使用数据库连接字符串进行查询等处理, 入坑
入坑.!!!!! SSIS 中dts包 设置的 ADO.Net连接, 在传入脚本的时候, 我要使用 数据库连接,进行数据的删除操作. 于是我使用了 了如下的 代码 使用的是windows 身份验证, ...
- webpack入坑之旅(六)配合vue-router实现SPA
这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...
- webpack入坑之旅(五)加载vue单文件组件
这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...
随机推荐
- 你了解栈溢出StackOverFloweExeption的原理吗?
StackOverflowException的常见几种引起的方式 1.类的相互引用 2.方法的循环调用 3.属性Set方法的死循环调用 class Program : IProgram { IPers ...
- UTF-8的BOM含义
BOM的介绍 在github上写md文件的时候,发现生成自己blog时,报出一个错误是让使用UTF-8编码,然后在Notepad++上把文件转成UTF-8时,发现菜单中有"UTF-8无BOM ...
- Mybatis第二天
Mybatis第二天 框架课程 1. 课程计划 1.输入映射和输出映射 a) 输入参数映射 b) 返回值映射 2.动态sql a) If标签 b) Where标签 c) Sql片段 d) Fore ...
- mycat跟踪分析
mycat版本1.6 192.168.5.66 从 192.168.5.67主 一个user表 验证主从 log4j2修改日志level为debug schema.xml配置 启动服务,打开日志tai ...
- Python开发——16.HTML
一.HTML 1.服务端 import socket def main(): sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock. ...
- 针对zstack虚拟机导出的问题的解决办法!
1. nfs 首先定位image所在位置: 云主机--〉云盘操作--〉配置信息--〉更多信息--安装路径 /opt/zstack/nfsprimarystorage/prim-aab63dc6284f ...
- 【python-时间戳】时间与时间戳之间的转换
对于时间数据,如2016-05-05 20:28:54,有时需要与时间戳进行相互的运算,此时就需要对两种形式进行转换,在Python中,转换时需要用到time模块,具体的操作有如下的几种: 将时间转换 ...
- Codeforces831D Office Keys
D. Office Keys time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...
- git忽视修改的文件
对于tracked文件来说,使用.gitignore是不行的.但是git提供了新的方法. 使用命令 git update-index --assume-unchanged <files>, ...
- Promise实践
一.概念 Promise是异步编程的解决方案之一,与事件驱动+回调函数并列. Promise是专门为异步编程设计的封闭的一次性用品,封闭体现在只有异步操作的结果能改变其状态,其他任何操作都不能改变其状 ...