父类子类初始化问题
2015-10-11 11:42
253 查看
携程Java工程师的移到面向对象面试题
输出是null
来自未老莫还乡 的评论:
【不要在构造器里调用可能被重载的虚方法,这是极度危险的】。构造器的初始化顺序大概是 父类静态块 子类静态块 父类初始化语句 父类构造函器 子类初始化语句 子类构造器。父类构造器执行的时候,调用了子类的重载方法,然而子类的类字段还在刚初始化的阶段,刚完成内存布局,只能输出null。
来自ihuning 的精华评论:
看我大师归来:
1. Base b = new Sub();
2. Base b = 直接忽略,从 new Sub();开始
3. 类加载器加载 Base,Sub 类到jvm;
4. 为Base,Sub 类中的两个属性baseName 分配存储空间,但是不初始化;
注意:属性的初始化时放在构造器中,按照代码顺序执行的。
5. new Sub会调用Sub的无参构造器,而在这个构造器中会隐式调用父类Base的无参构造器;
6. 父类Base的构造器中代码本质是
public Base()
{
baseName = "base";
callName();
}
即父类的属性baseName 的值为base。但为何输出null,骚年别急。
7. 因为父类构造器方法是在子类中调用的,即大环境是子类。此时,调用的方法callName()当然是指子类的方法。而这个方法打印的属性baseName当然也是子类的。那现在子类的属性baseName的值是多少呢?答案是null.因为此时子类Sub的构造器内代码本质是:
super();
baseName="sub";
此时baseName="sub"还没执行。
因此,左后的值当然是null.
个人总结:
main方法之前先把父类初始化,包括父类static块,然后子类static块(因为main方法中new了子类)
然后父类默认的构造函数,然后子类构造函数
输出:
construct-parent-before
sub
construct-parent-after
construct-sub
public class Base { private String baseName = "base"; public Base() { callName(); } public void callName() { System.out.println(baseName); } static class Sub extends Base { private String baseName = "sub"; public void callName() { System.out.println(baseName); } } public static void main(String[] args) { Base b = new Sub(); } }
输出是null
来自未老莫还乡 的评论:
【不要在构造器里调用可能被重载的虚方法,这是极度危险的】。构造器的初始化顺序大概是 父类静态块 子类静态块 父类初始化语句 父类构造函器 子类初始化语句 子类构造器。父类构造器执行的时候,调用了子类的重载方法,然而子类的类字段还在刚初始化的阶段,刚完成内存布局,只能输出null。
来自ihuning 的精华评论:
看我大师归来:
1. Base b = new Sub();
2. Base b = 直接忽略,从 new Sub();开始
3. 类加载器加载 Base,Sub 类到jvm;
4. 为Base,Sub 类中的两个属性baseName 分配存储空间,但是不初始化;
注意:属性的初始化时放在构造器中,按照代码顺序执行的。
5. new Sub会调用Sub的无参构造器,而在这个构造器中会隐式调用父类Base的无参构造器;
6. 父类Base的构造器中代码本质是
public Base()
{
baseName = "base";
callName();
}
即父类的属性baseName 的值为base。但为何输出null,骚年别急。
7. 因为父类构造器方法是在子类中调用的,即大环境是子类。此时,调用的方法callName()当然是指子类的方法。而这个方法打印的属性baseName当然也是子类的。那现在子类的属性baseName的值是多少呢?答案是null.因为此时子类Sub的构造器内代码本质是:
super();
baseName="sub";
此时baseName="sub"还没执行。
因此,左后的值当然是null.
个人总结:
main方法之前先把父类初始化,包括父类static块,然后子类static块(因为main方法中new了子类)
然后父类默认的构造函数,然后子类构造函数
public class Base { private static String baseName = "base"; public Base() { System.out.println("construct-parent-before"); callName(); System.out.println("construct-parent-after"); } public void callName() { System.out.println(baseName); } static class Sub extends Base { private static String baseName = "sub"; public Sub(){ System.out.println("construct-sub"); } public void callName() { System.out.println(baseName); } } public static void main(String[] args) { new Sub(); } }
输出:
construct-parent-before
sub
construct-parent-after
construct-sub
相关文章推荐
- mybatis05 用户添加
- [软考]之原码、反码、补码和移码
- SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段值)
- IOSi科研OS7 具体的使用说明的适应
- 关于linux中的时间 时区问题
- 学习C++的50条忠告(转载)
- NEON 编程
- 与 Hadoop 对比,如何看待 Spark 技术?
- 如何在Win8.1中找到系统原带的画图工具
- 对vibe背景建模的一点理解
- QQ接口接入
- Linux变成路由器
- [Andorid]按钮设计
- 《学习OpenCV》第四章课后题9
- hdu 5500 Reorder the Books 【BestCoder Round #59 (div.2) 第二题】
- GCD
- LeetCode-Contains Duplicate III
- 个人学习笔记——数据库:主键和外键
- web数据库设计过程
- 【Ubuntu14.04.1】设置开机可以Root用户身份登录