java类初始化顺序的影响
来源:互联网 发布:微盘外汇交易平台源码 编辑:程序博客网 时间:2024/06/07 20:08
问题描述:在网上看到一个笔试题,由下列代码输出打印结果为null,为什么?
详细查看http://blog.csdn.net/two_water/article/details/53891952这篇博客
package test;public class Base { private String name ="base"; public Base() { callName(); } public void callName() { System.out.println(name); } static class Sub extends Base { private String name = "sub"; public void callName() { System.out.println(name); } } public static void main(final String[] args) { Base base = new Sub(); }}
突然间发现自己也不是很清楚,于是阅读了上面的那篇文章,写的很好,浅显易懂。最关键的是理解下面这段代码以及构造器的初始化顺序大概是:父类静态块 ->子类静态块 ->父类初始化语句 ->父类构造函器 ->子类初始化语句 -> 子类构造器,也就清楚了代码的执行流程。
public Sub(){ super(); baseName = "sub"; }
但是一个同事看后问我,此时Base类中的name的值是什么?这由提出了另外一个问题,也就是在类的构造函数中,super()、类变量初始化、代码块中代码,他们的顺序又是怎么样?为了得出答案,我通过javap -verbose Base指令将Base.class文件打印出来查看Base.:()V的具体指令时发现了答案。
aload_0
invokespecial #1; //Method java/lang/Object.””:()V
aload_0
ldc #2; //String base
putfield #3; //Field name:Ljava/lang/String;
aload_0
invokevirtual #4; //Method callName:()V
return
从上面可以看出,一个类的构造方法的指令是从父类构造方法先执行,然后进行类变量初始化,最后才是放在构造方法中代码的执行,也即
public Base() { super(); //先父类构造方法 name = "base"; //接着类变量初始化 callName(); // 最后才是代码块的执行}
问题似乎得到解决,那么在来一波程序进行分析,此时答案为多少?
package test;public class InitialClass { public int i = methodI(); public static int j = methodJ(); public int k = 0; public InitialClass() { System.out.println(1); } public int methodI() { System.out.println(2); return 2; } public static int methodJ() { System.out.println(3); return 3; } static class B extends InitialClass { public int m = methodM(); public static int n = methodN(); public int t = 0; public B() { System.out.println(4); } public int methodM() { System.out.println(5); return 5; } public static int methodN() { System.out.println(6); return 6; } } public static void main(final String[] args) { System.out.println(7); InitialClass a = new B(); a.toString(); }}
只要记住上面提到过的类构造器的初始化顺序大概是:父类静态块 ->子类静态块 ->父类初始化语句 ->父类构造函器 ->子类初始化语句 -> 子类构造器。一般会认为答案是
7
3
6
2
1
5
4
但是通过编译、执行发现答案是
3
7
6
2
1
5
4
依据类构造器的顺序我们可以理解3、6的顺序,那么为什么7会在3、6之间输出呢?问题似乎又变得有意思起来。其实转弯理解main方法是InitialClass类的静态方法,jvm是从InitialClass类的main作为程序入口进行执行,那么首先得加载InitialClass类,此时会初始化静态变量j,也就执行了methodJ()静态方法,在进行new B()时,此时父类InitialClass已经加载,则执行B中的静态类变量初始,在依次执行父类构造器、子类构造器从而得出结果。
- java类初始化顺序的影响
- Java 中的初始化顺序的影响和“overloading”与“overwrite”
- 类的成员变量 声明顺序 决定 初始化顺序(构造函数初始化列表不影响)
- java类的初始化顺序
- Java类的初始化顺序
- Java类的初始化顺序
- Java类的初始化顺序
- Java类的初始化顺序
- java类初始化的顺序
- java类的初始化顺序
- Java类的初始化顺序
- java 类的初始化顺序
- Java类的初始化顺序
- java类的初始化顺序
- java类的初始化顺序
- JAVA类的初始化顺序
- Java类的初始化顺序
- java类的初始化顺序
- jQuery 教程
- 硕士研究生考试总结
- 获取当前线程名称
- SpringCloud分布式开发五大神兽
- TEC1303.Form个性化技术总结 - 第一部分 Form个性化技术讲解
- java类初始化顺序的影响
- JS基础——DOM树结构
- jQuery 简介
- CS231n作业笔记2.2:多层神经网络的实现
- Druid——Hadoop-based Batch Ingestion
- jQuery 安装
- ubantu下环境搭建lamp环境
- ubuntu安装ssh
- jQuery 语法