牛刀小试1.
试一把静态代码块、实例化代码块和构造函数的执行顺序
public class People { public static int num = 0;//静态变量初始化 String name;//初始化为null //构造函数 public People(String name) { System.out.println(num + ":构造函数初始化"); this.name = name; //将name引用指向传入参数 num++; //构造函数执行结束num值+1 } //实例初始化块 { System.out.println(num + ":实例初始化块"); } //静态初始化块 static { System.out.println(num + ":静态初始化块"); } public static void main(String[] args) { People people1 = new People("xunzhaorendaxia"); People people2 = new People("xunzhaorendaxia"); } }
输出结果:
0:静态初始化块 0:实例初始化块 0:构造函数初始化 1:实例初始化块 1:构造函数初始化
反编译后的代码:
public class People { public static int num = 0; String name; public People(String name) { System.out.println(num + ":实例初始化块"); System.out.println(num + ":构造函数初始化"); this.name = name; num += 1; } public static void main(String[] args) { People people1 = new People("xunzhoarendaxia"); People people2 = new People("xunzhaorendaxia"); } static { System.out.println(num + ":静态初始化块"); } }
结论:
1)执行先后顺序,静态初始化块>实例初始化块>构造函数初始化。 2)静态初始化块只在类加载时执行一次,实例初始化块和构造函数初始化每次实例化类时都执行。 3)实例初始化块的代码,其实被放进了构造函数里面,且放在构造函数内容的前面。
牛刀小试2.
测试一种初始化HashMap的方式(使用场景是想优雅的初始化一些Key-Value的参数):
public class Person { public static int num = 0;//静态变量初始化 String name;//初始化为null //构造函数 public Person(String name) { System.out.println(num + ":构造函数初始化"); this.name = name; //将name引用指向传入参数 num++; //构造函数执行结束num值+1 } //实例初始化块 { System.out.println(num + ":实例初始化块"); } static Map map1=null; //静态初始化块 static { System.out.println(num + ":静态初始化块"); map1 = new HashMap<String,String>(){ { put("1", "111"); put("2", "2222"); } }; } public final static Map map = new HashMap(); public static void main(String[] args) { Person people1 = new Person("xunzhaorendaxia"); Person people2 = new Person("xunzhaorendaxia"); System.out.println(map1.toString()); } }
输出内容:
0:静态初始化块 0:实例初始化块 0:构造函数初始化 1:实例初始化块 1:构造函数初始化 {1=111, 2=2222}
反编译文件中会出现两个class文件:
下面是反编译的代码:
public class Person { public static int num = 0; String name; static Map map1 = null; public static final Map map; static { System.out.println(num + ":静态初始化块"); map1 = new 1();//这里new 1()肯定是编译优化的,怎么简单省空间怎么来。 map = new HashMap(); } public Person(String name) { System.out.println(num + ":实例初始化块"); System.out.println(num + ":构造函数初始化"); this.name = name; ++num; } public static void main(String[] args) { new Person("xunzhaorendaxia"); new Person("xunzhaorendaxia"); System.out.println(map1.toString()); } }
class Person$1 extends HashMap<String, String> { Person$1() { this.put("1", "111"); this.put("2", "2222"); } }
下面提出个人的解析观点:
1.Person$1的class文件怎么回事?
答:Person$1.class是内部类的编译文件,即Person类中名为“1”的匿名内部类的编译文件。“1”应该是编译器优化了这里的匿名内部类。(注意查看第二个反编译文件)
2.为啥会出现匿名内部类?好像没有定义啊
答:请注意这里的Person类中HashMap的初始化方式,后面加了{{}}两层大括号,这里第一个外层{}编译器默认是编译成一个继承HashMap的匿名内部类。第二个内层{}本质上是属于实例代码块,即在执行构造方法是最先执行。(不明白的可以参考牛刀小试1)。还有一点需要注意这里的静态代码块初始化HashMap的声明要放在外面,写在静态代码块中会读不到(作用域不够)。
static Map map1=null; //静态初始化块 static { System.out.println(num + ":静态初始化块"); map1 = new HashMap<String,String>(){ { put("1", "111"); put("2", "2222"); } }; }
参考链接:https://www.cnblogs.com/xdouby/p/5890083.html
https://blog.csdn.net/kingzone_2008/article/details/45015301