今天遇到一个关于静态代码块和非静态代码块执行的问题。先看如下程序。
package com.zpj.classload; /** * @author Perkins Zhu * @version 2017年1月17日 下午8:07:34 */ public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } { A = 8; System.out.println("Non Static code block----" + A); } StaticClass() { this(A); A = 3; System.out.println("Construction method----" + A); } StaticClass(int i) { A = i; System.out.println("Construction method with parameters----" + A); } public static void main(String[] args) { StaticClass sc = new StaticClass(); } }
程序运行结果如下:
Static code block----6 Non Static code block----8 Construction method with parameters----6 Construction method----3
对于前两行的输出倒是没什么疑问,加载的时候先加载静态代码块然后加载非静态代码块,静态代码块只在加载类的时候加载一次,而非静态代码块在每次new一个对象的时候进行加载。可第三行的那个A明明已经赋值为8了,可为什么还输出一个6呢?
于是打断点走了一次发现,在执行到this(A);的时候,程序直接掉到非静态代码块中进行执行。执行完非静态代码块之后才继续纸箱带参构造方法。怪了!!!
找不到原因,便决定生成class文件然后反编译一下看看反编译之后的代码如何。这一反编译便找到了原因,看反编译之后的代码:
import java.io.PrintStream; public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } StaticClass() { this(A); A = 3; System.out.println("Construction method----" + A); } StaticClass(int paramInt) { //注意如下两行,原来的非静态代码块中的内容被加载到了含参构造器中 A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } public static void main(String[] paramArrayOfString) { StaticClass localStaticClass = new StaticClass(); } }
非静态代码块消失了,被加载到含参构造器中。这便解释了为什么会出现上面的这种情况,同时也解释了为何非静态代码块会在每次new对象的时候都要加载一次。
那么,问题又来了。为什么非静态代码块会被加载到含参构造器中而没有加载到不含参构造器中呢?
下面又重新更改代码:去掉含参构造器之后
package com.zpj.classload; /** * @author Perkins Zhu * @version 2017年1月17日 下午8:07:34 */ public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } { A = 8; System.out.println("Non Static code block----" + A); } StaticClass() { A = 3; System.out.println("Construction method----" + A); } public static void main(String[] args) { StaticClass sc = new StaticClass(); } }
反编译结果
import java.io.PrintStream; public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } StaticClass() {
A = 8; System.out.println("Non Static code block----" + A); A = 3; System.out.println("Construction method----" + A); } public static void main(String[] paramArrayOfString) { StaticClass localStaticClass = new StaticClass(); } }
去掉不含参构造方法
package com.zpj.classload; /** * @author Perkins Zhu * @version 2017年1月17日 下午8:07:34 */ public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } { A = 8; System.out.println("Non Static code block----" + A); } StaticClass(int i) { A = i; System.out.println("Construction method with parameters----" + A); } public static void main(String[] args) { StaticClass sc = new StaticClass(2); } }
反编译之后如下:
import java.io.PrintStream; public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } StaticClass(int paramInt) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } public static void main(String[] paramArrayOfString) { StaticClass localStaticClass = new StaticClass(2); } }
再添加一个两个参数的构造器
package com.zpj.classload; /** * @author Perkins Zhu * @version 2017年1月17日 下午8:07:34 */ public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } { A = 8; System.out.println("Non Static code block----" + A); } StaticClass() { this(A); A = 3; System.out.println("Construction method----" + A); } StaticClass(int i) { A = i; System.out.println("Construction method with parameters----" + A); } StaticClass(int i, String name) { A = i; System.out.println("Construction method with parameters----" + A); } public static void main(String[] args) { StaticClass sc = new StaticClass(); } }
反编译之后:
import java.io.PrintStream; public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } StaticClass() { this(A); A = 3; System.out.println("Construction method----" + A); } StaticClass(int paramInt) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } StaticClass(int paramInt, String paramString) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } public static void main(String[] paramArrayOfString) { StaticClass localStaticClass = new StaticClass(); } }
再添加一个三个参数的构造器
package com.zpj.classload; /** * @author Perkins Zhu * @version 2017年1月17日 下午8:07:34 */ public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } { A = 8; System.out.println("Non Static code block----" + A); } StaticClass() { A = 3; System.out.println("Construction method----" + A); } StaticClass(int i) { A = i; System.out.println("Construction method with parameters----" + A); } StaticClass(int i, String name) { A = i; System.out.println("Construction method with parameters----" + A); } StaticClass(int i, String name, String whatever) { A = i; System.out.println("Construction method with parameters----" + A); } public static void main(String[] args) { StaticClass sc = new StaticClass(); } }
反编译之后:
import java.io.PrintStream; public class StaticClass { static int A = 5; static { A = 6; System.out.println("Static code block----" + A); } StaticClass() {
A = 8; System.out.println("Non Static code block----" + A); A = 3; System.out.println("Construction method----" + A); } StaticClass(int paramInt) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } StaticClass(int paramInt, String paramString) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } StaticClass(int paramInt, String paramString1, String paramString2) { A = 8; System.out.println("Non Static code block----" + A); A = paramInt; System.out.println("Construction method with parameters----" + A); } public static void main(String[] paramArrayOfString) { StaticClass localStaticClass = new StaticClass(); } }
注意带下划线的地方,如果调用this()其他构造器的构造器便没有添加非静态代码块的代码,没有调用的构造器则每个都有。
得出结论:
非静态代码块在进行编译的时候,会自动把非静态代码块中的代码复制到所有没有调用其他构造器的构造器中。