Java语法专题1: 类的构造顺序
- 合集目录
- Java语法专题1: 类的构造顺序
问题
下面的第二个问题来源于Oracle的笔试题, 非常经典的一个问题, 我从07年开始用了十几年. 看似简单, 做对的比例不到2/10.
- 描述一下多级继承中类的构造顺序
- 给定两段代码, 分别是父类和子类, 写出(或选择)正确的输出
代码如下
public class Base {
public Base() {
method(100);
}
public void method(int i) {
System.out.println("Base::method " + i);
}
}
public class Sub extends Base {
public Sub() {
super.method(70);
}
public void method(int j) {
System.out.println("Sub::method " + j);
}
public void method(String j) {
System.out.println("Sub::passed " + j);
}
public static void main(String[] args) {
Base b1 = new Base();
Base b2 = new Sub();
}
}
分析
这是属于Java中常见的基础概念问题, 正确回答这些问题, 需要对类的这些知识有清晰的了解:
- Java类实例的初始化顺序
- Java类方法的重写, 以及和重载的区别
以下通过具体场景说明
场景一
先看下面代码, 执行Sub.java时的屏幕输出是什么?
Base.java
public class Base {
public Base() {
method(100);
}
public void method(int i) {
System.out.println("Base::method " + i);
}
}
Sub.java
public class Sub extends Base {
public void method(int j) {
System.out.println("Sub::method " + j);
}
public static void main(String args[]) {
Base b2 = new Sub();
}
}
这里有两个很重要的概念:
- 类初始化时隐藏的构造顺序: 先调用父类的默认构造函数(即不带参数的构造函数), 然后再执行当前构造函数, 因为本例中Sub.java的构造函数为空(未定义), 因此实际执行的是父类的默认构造函数
- 父类的函数, 会被子类定义的同参数方法覆盖, 这叫方法重写. 本例中初始化的类是Sub, Sub中的method(int i), 已经重新定义, 因此父类的默认构造函数中调用的是Sub的method(int i).
输出
Sub::method 100
场景二
保持父类Base.java不变, 在Sub.java中增加子类的构造函数, 执行Sub.java时的屏幕输出是什么?
public class Sub extends Base {
public Sub() {
super.method(70);
}
public void method(int j) {
System.out.println("Sub::method " + j);
}
public static void main(String args[]) {
Base b2 = new Sub();
}
}
第一行的输出可以参照场景一的说明, 初始化Sub时, 会隐藏调用父类的默认构造函数, 第二行则是子类构造函数中, 在super.method(70);中指定使用父类的method(int i)方法产生的结果.
这个输出验证了前面说的类初始化时的隐藏初始化顺序: 会先调用父类的默认构造函数(即不带参数的构造函数), 然后再执行当前构造函数里的逻辑. 这是最容易出错地方, 漏了第一行, 忘记了即使子类定义了构造函数, 父类构造函数一样会执行.
输出是
Sub::method 100
Base::method 70
场景三
再验证一下类初始化时的隐藏初始化顺序, 如果父类和子类都增加了带变量的构造函数, 执行Sub.java时的屏幕输出是什么?
Base.java
public class Base {
public Base() {
method(100);
}
public Base(int i) {
method(i);
}
public void method(int i) {
System.out.println("Base::method " + i);
}
}
Sub.java
public class Sub extends Base {
public Sub(int i) {
super.method(70);
}
public void method(int j) {
System.out.println("Sub::method " + j);
}
public static void main(String args[]) {
//Base b1 = new Base();
Base b2 = new Sub(100);
}
}
依然先调用了父类的默认构造函数(不带参数), 再调用子类的构造函数, 输出是
Sub::method 100
Base::method 70
场景四
父类不带默认构造函数
Base.java
public class Base {
public Base(int i) {
method(i);
}
public void method(int i) {
System.out.println("Base::method " + i);
}
}
此时Sub.java如果还使用前一个场景的代码, 就会无法通过编译, 因为找不到父类的默认构造函数了, 此时隐藏的初始化顺序就失效了, 需要指定使用哪个父类构造函数
Sub.java
public class Sub extends Base {
public Sub(int i) {
super(100); // <------- 需要显式指定构造函数
super.method(70);
}
public void method(int j) {
System.out.println("Sub::method " + j);
}
public static void main(String args[]) {
//Base b1 = new Base();
Base b2 = new Sub(100);
}
}
执行Sub.java时的屏幕输出依然是
Sub::method 100
Base::method 70
总结
问题: 描述一下多级继承中类的构造顺序
解答:
- 类初始化时的隐藏逻辑: 先调用父类的默认构造函数, 再调用子类的默认构造函数
- 当父类定义了带参数的构造函数, 又不定义默认构造函数时, 上一条就失效了, 子类必须显式指定父类的构造函数
Java语法专题1: 类的构造顺序的更多相关文章
- Java语法专题2: 类变量的初始化顺序
合集目录 Java语法专题2: 类变量的初始化顺序 问题 这也是Java面试中出镜率很高的基础概念问题 描述一下多级继承中字段初始化顺序 描述一下多级继承中类变量初始化顺序 写出运行以下代码时的控制台 ...
- c++ 类的构造顺序
在单继承的情况下,父类构造先于子类,子类析构先于父类,例: class A { public: A() { cout << "A" << endl; } ~ ...
- 从Java虚拟机角度分析类的实例化顺序
1.首先展示一下实例代码(Son.java & Father.java) public class Father { public static int a=10;//父类的静态变量 stat ...
- c# 衍生类和基类的构造顺序
public class MyDeriveClass :MyBaseClass { public MyDeriveClass() :base() { } int derive_int = 1; } p ...
- java类的初始化顺序
在java中,当我们new一个对象时,对象中的成员,初始化块以及构造方法的加载是有一定的顺序的,看下面一副图: 一.单类(无基类)下的初始化顺序: public class Parent { stat ...
- java中带继承类的加载顺序详解及实战
一.背景: 在面试中,在java基础方面,类的加载顺序经常被问及,很多时候我们是搞不清楚到底类的加载顺序是怎么样的,那么今天我们就来看看带有继承的类的加载顺序到底是怎么一回事?在此记下也方便以后复习巩 ...
- C++类继承中,基类/当前对象属性/当前对象的构造顺序
[1]中提到,规范的派生类构造函数三个要点: 首先创建基类对象 应通过成员初始化列表,创建基类对象 应该初始化本派生类新增的成员变量 那在构造派生类实例的过程中,其基类(以及多继承的时候多个基类)/当 ...
- java学习(一)静态代码块 构造代码块 构造方法的执行顺序及注意问题
今天我总结了一下java中静态代码块 构造代码块 构造方法的执行顺序及其注意问题 首先要知道静态代码块是随着类的加载而加载,而构造代码块和构造方法都是随着对象的创建而加载 当时做了这么一个小案例(想必 ...
- 比较C++、Java、Delphi声明类对象时候的相关语法
同学们在学习的时候经常会遇到一些问题,C++.Java.Delphi他们到底有什么不一样的呢?今天我们来比较C++.Java.Delphi声明类对象时候的相关语法.希望对大家有帮助! C++中创建对象 ...
随机推荐
- 【LeetCode】768. Max Chunks To Make Sorted II 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/max-chun ...
- 【LeetCode】848. Shifting Letters 解题报告(Python)
[LeetCode]848. Shifting Letters 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...
- 『学了就忘』vim编辑器基础 — 97、vim使用技巧
目录 1.在vim中导入其他文件内容或命令结果 (1)导入其他文件内容 (2)在vim中执行系统命令 (3)导入命令结果 2.设定快捷键 3.字符替换 4.多文件打开 vim使用技巧,就是vim编辑器 ...
- SpringMVC 五大组件
DispatcherServlet HandleMapping Controller ModeAndView ViewResolver 1.DispatcherServlet 这个控件是SpringM ...
- 「算法笔记」Min_25 筛
戳 这里(加了密码).虽然写的可能还算清楚,但还是不公开了吧 QwQ. 真的想看的 私信可能会考虑给密码 qwq.就放个板子: //LOJ 6053 简单的函数 f(p^c)=p xor c #inc ...
- Null和空值对于avg计算时产生的影响以及处理
为什么要关注这一块呢:1.面试中可能会有涉及 2.工作中真的也可能会用,既然有可能我也用过,就拿出来跟大家分享一下,上一篇的博文,数据已准备好就不做数据准备的介绍了. step1:select * f ...
- gogs安装与说明(docker)
作为一个开发,少不了和git打交道,像github,gitee是很流行的git线上托管平台,而我们也搭建自己的git托管平台,有条件的可以使用gitlab,它对硬件有要求,像博主这种没条件用虚拟机的, ...
- Kafka基础教程(二):Kafka安装
因为kafka是基于Zookeeper的,而Zookeeper一般都是一个分布式的集群,尽管kafka有自带Zookeeper,但是一般不使用自带的,都是使用外部安装的,所以首先我们需要安装Zooke ...
- 论文翻译:2020_A Robust and Cascaded Acoustic Echo Cancellation Based on Deep Learning
论文地址:https://indico2.conference4me.psnc.pl/event/35/contributions/3364/attachments/777/815/Thu-1-10- ...
- CF858D Polycarp's phone book
题意翻译 有 n 个长度为 9 且只包含数字字符互不相同的串. 需要对于每个串找到一个长度最短的识别码,使得这个识别码当且仅当为这个串的子串. 题目分析 因为范围不是非常大,所以可以将子串筛出来 然后 ...