疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java类的初始化顺序


 

 
最近项目上工作强度还是蛮紧张的,技术还是公司框架自身封装好的(spring+mvc+mybatis+js+jquery+json+shiro+cacheEnable+swagger+ajax+反射等等几十项框架及插件),基础的原理还是没有脱离java的基础知识。今天抽个空把java类的初始化顺序整理一下(最近发现的一个规律,我之前用心总结的博客内容,在工作中用到的频次还是非常高的,所以好记性不如烂笔头,坚持总结、实践吧,骚年)。
 
一、构造器初始化
 
复制代码
package com.edu;
 
class Window {
    Window(int marker) {
        System.out.println("window(" + marker + ")");
    }
}
 
class House {
    Window w1 = new Window(1);
 
    House() {
        w3 = new Window(33);
    }
 
    Window w2 = new Window(2);
 
    void f() {
        System.out.println("f()");
    }
 
    Window w3 = new Window(3);
}
 
public class OrderOfInitialization {
    public static void main(String[] args) {
        House h = new House();
        h.f();
    }
}
结果:
window(1)
window(2)
window(3)
window(33)
f()
复制代码
①:初始化可以放在构造器内部;
 
②:House类在new对象时,会对内部的所有变量进行初始化,所以你看到的是先进行window(1)、window(2)、window(3)的初始化;
 
③:window(3)被初始化了两次
 
 
 
二、静态数据的初始化
 
复制代码
package com.edu;
 
/**
 * 静态数据的初始化
 * 
 * @author tery
 *
 */
class Bowl {
    Bowl(int marker) {
        System.out.println("Bowl(" + marker + ")");
    }
    void f1(int marker) {
        System.out.println("f1(" + marker + ")");
    }
}
 
class Table {
    static Bowl bowl1 = new Bowl(1);
 
    Table() {
        System.out.println("Table");
        bowl2.f1(1);
    }
    void f2(int marker) {
        System.out.println("f2(" + marker + ")");
    }
    static Bowl bowl2 = new Bowl(2);
}
 
class CupBoard {
    Bowl bowl3 = new Bowl(3);
    static Bowl bowl4 = new Bowl(4);
 
    CupBoard() {
        System.out.println("CupBoard()");
        bowl4.f1(2);
    }
    void f3(int marker) {
        System.out.println("f3(" + marker + ")");
    }
    static Bowl bowl5 = new Bowl(5);
}
 
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
//        System.out.println("Creating new CupBoard() in main");
//        new CupBoard();
//        table.f2(1);
//        cupboard.f3(1);
    }
//    static Table table=new Table();
//    static CupBoard cupboard=new CupBoard();
}
 
结果:
Creating new CupBoard() in main
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
复制代码
为了看清楚,把注释掉的代码逐步放开:
复制代码
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
//        System.out.println("Creating new CupBoard() in main");
 
//        new CupBoard();
//        table.f2(1);
//        cupboard.f3(1);
    }
    static Table table=new Table();
//    static CupBoard cupboard=new CupBoard();
}
结果:
Bowl(1)
Bowl(2)
Table
f1(1)
Creating new CupBoard() in main
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
复制代码
 
 
复制代码
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
//        System.out.println("Creating new CupBoard() in main");
//        new CupBoard();
//        table.f2(1);
//        cupboard.f3(1);
    }
    static Table table=new Table();
    static CupBoard cupboard=new CupBoard();
}
结果:
Bowl(1)
Bowl(2)
Table
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
Creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
复制代码
 
 
复制代码
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
//        table.f2(1);
//        cupboard.f3(1);
    }
    static Table table=new Table();
    static CupBoard cupboard=new CupBoard();
}
结果:
Bowl(1)
Bowl(2)
Table
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
Creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
Creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
复制代码
 
 
复制代码
public class StaticInitialization {
    public static void main(String[] args) {
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
        System.out.println("Creating new CupBoard() in main");
        new CupBoard();
        table.f2(1);
        cupboard.f3(1);
    }
    static Table table=new Table();
    static CupBoard cupboard=new CupBoard();
}
结果:
Bowl(1)
Bowl(2)
Table
f1(1)
Bowl(4)
Bowl(5)
Bowl(3)
CupBoard()
f1(2)
Creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
Creating new CupBoard() in main
Bowl(3)
CupBoard()
f1(2)
f2(1)
f3(1)
复制代码
 
 
小总结:
 
①无论创建多少个对象,静态数据都只占一份存储区域。static关键字不能应用于局部变量,因此它只能作用于域。如果一个域是静态的基本类型域,且没有对它进行初始化,那么它就会获得基本类型的标准初值,如果它是对象的引用,那么它的默认初始化的值就是null。
 
②初始化的顺序是先静态对象(如果它们尚未因前面的对象创建过程而被初始化),而后是非静态对象。
 
③要执行main()(静态方法),必须加载StaticInitialization类,紧接着其静态域table和cupboard被初始化,这将导致他们对应的类也被加载,并且由于它们也都包含静态的Bowl对象,因此Bowl随后也被加载。
 
三、.class创建对象
 
复制代码
package com.edu;
 
import java.util.Random;
 
/**
 * .class属性的初始化
 * @author tery
 *
 */
class Initable{
    Initable(){
        System.out.println("Initable initial...");
        }
    static final String staticFinal="47";
    static final int staticFinal2=ClassInitialization.rand.nextInt(1000);
    static{
        System.out.println("Initializing Initable");
    }
}
class Initable2{
    static int staticNonFinal=147;
    static{
        System.out.println("Initializing Initable2");
    }
}
class Initable3{
    static int staticNonFinal =74;
    static {
        System.out.println("Initializing Initable3");
    }
}
public class ClassInitialization {
public static Random rand=new Random(47);
public static void main(String[] args){
    Class initable=Initable.class;
    System.out.println("After creating Initable ref");
    System.out.println(Initable.staticFinal);
    Initable a=new Initable();
    System.out.println(Initable.staticFinal2);
//    System.out.println(Initable2.staticNonFinal);
//    System.out.println(Initable3.staticNonFinal);
}
}
结果:
After creating Initable ref
47
Initializing Initable
Initable initial...
258
复制代码
为了使用类而准备的工作实际上包含三个步骤:
 
①加载,这是由类加载器执行的,该步骤将查找字节码(通常在classpath所指定的路径中查找,但这并非是必须的),并从这些字节码中创建一个Class对象。
 
②链接,在链接阶段将验证类中的字节码,为静态域分配存储空间,并且如果必须的话,将解析这个类创建的对其他类的所有引用。
 
③初始化,如果该类具有超类,则对其进行初始化,执行静态初始化器和静态初始化块。初始化被延迟到了对静态方法(构造器隐式地是静态的)或者非常数静态域进行首次引用时才执行。
 
④在打印Initable.staticFinal时属于调用常数静态域,即使加上Initable(){...}的构造方法,也不会执行,将int型改为String型也是同样的结果。