Java代码
class Parent{
static String name = "hello";
static {
System.out.println("parent static block");
}
{
System.out.println("parent block");
}
public Parent(){
System.out.println("parent constructor");
}
}
class Child extends Parent{
static String childName = "hello";
static {
System.out.println("child static block");
}
{
System.out.println("child block");
}
public Child(){
System.out.println("child constructor");
}
}
public class StaticIniBlockOrderTest {
public static void main(String[] args) {
new Child();//语句(*)
}
}
问题:当执行完语句(*)时,打印结果是什么顺序?为什么?
解答:当执行完语句(*)时,打印结果是这样一个顺序:parent static block,child static block,parent block,parent constructor,child block,child constructor。
分析:当执行new Child()时,它首先去看父类里面有没有静态代码块,如果有,它先去执行父类里面静态代码块里面的内容,当父类的静态代码块里面的内容执行完毕之后,接着去执行子类(自己这个类)里面的静态代码块,当子类的静态代码块执行完毕之后,它接着又去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法,这个就是一个对象的初始化顺序。
总结:对象的初始化顺序:首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。
父类Static->子类static->父类缺省{}->父类构造函数->子类缺省{}->子类构造函数
(静态变量、静态初始化块)>(变量、初始化块)>构造器
注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。
Java代码
class Parent {
// 静态变量
public static String p_StaticField = "父类--静态变量";
// 变量
public String p_Field = "父类--变量";
// 静态初始化块
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
// 初始化块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
// 构造器
public Parent() {
System.out.println("父类--构造器");
}
}
public class SubClass extends Parent {
// 静态变量
public static String s_StaticField = "子类--静态变量";
// 变量
public String s_Field = "子类--变量";
// 静态初始化块
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
// 初始化块
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
// 构造器
public SubClass() {
System.out.println("子类--构造器");
}
// 程序入口
public static void main(String[] args) {
new SubClass();
}
}
[java] view plaincopy
class Parent {
// 静态变量
public static String p_StaticField = "父类--静态变量";
// 变量
public String p_Field = "父类--变量";
// 静态初始化块
static {
System.out.println(p_StaticField);
System.out.println("父类--静态初始化块");
}
// 初始化块
{
System.out.println(p_Field);
System.out.println("父类--初始化块");
}
// 构造器
public Parent() {
System.out.println("父类--构造器");
}
}
public class SubClass extends Parent {
// 静态变量
public static String s_StaticField = "子类--静态变量";
// 变量
public String s_Field = "子类--变量";
// 静态初始化块
static {
System.out.println(s_StaticField);
System.out.println("子类--静态初始化块");
}
// 初始化块
{
System.out.println(s_Field);
System.out.println("子类--初始化块");
}
// 构造器
public SubClass() {
System.out.println("子类--构造器");
}
// 程序入口
public static void main(String[] args) {
new SubClass();
}
}
运行一下上面的代码,结果马上呈现在我们的眼前:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
可是静态代码块真的会一定在非静态代码块之前执行吗?
Java代码
public class ExA {
private static ExA a = new ExA();
static {
System.out.println("父类--静态代码块");
}
public ExA() {
System.out.println("父类--构造函数");
}
{
System.out.println("父类--非静态代码块");
}
public static void main(String[] args) {
new ExB();
}
}
class ExB extends ExA {
private static ExB b = new ExB();
static {
System.out.println("子类--静态代码块");
}
{
System.out.println("子类--非静态代码块");
}
public ExB() {
System.out.println("子类--构造函数");
}
}
[java] view plaincopy
public class ExA {
private static ExA a = new ExA();
static {
System.out.println("父类--静态代码块");
}
public ExA() {
System.out.println("父类--构造函数");
}
{
System.out.println("父类--非静态代码块");
}
public static void main(String[] args) {
new ExB();
}
}
class ExB extends ExA {
private static ExB b = new ExB();
static {
System.out.println("子类--静态代码块");
}
{
System.out.println("子类--非静态代码块");
}
public ExB() {
System.out.println("子类--构造函数");
}
}
执行结果
=====
父类--非静态代码块
父类--构造函数
父类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数
子类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数
=====
可以发现非静态代码块并不是一定在静态代码块之后执行的。
我认为此时private static ExA a = new ExA()是静态变量。而java里面静态变量与静态代码块是按代码先后顺序执行。所以就导致非静态代码块在静态代码块之前执行。