静态代码块、静态变量、成员变量等加载顺序详解
1 单个类的初始化顺序
一个类 无论创建多少对象,静态数据只占用一份存储区域,且只在类第一次初始化的时候进行静态数据初始化
顺序如下:
单个类而言: 静态变量/静态代码块 --> 成员变量(普通代码块) --> 构造方法 --> 静态方法
构造方法本身也是静态方法
栗子
public class TestStatic {
{
System.out.println("代码块1");
}
/*静态代码块*/
static {
System.out.println("静态代码块");
}
static Test test = new Test();
String s = "成员变量";
TestStatic (){
System.out.println(s + "TestStatic 构造方法");
}
{
System.out.println("代码块2");
}
public static void main(String[] args) {
new TestStatic();
}
}
class Test {
Test(){
System.out.println("test构造方法");
}
}
/*结果如下
静态代码块
test构造方法
代码块1
代码块2
成员变量TestStatic 构造方法
Process finished with exit code 0
说明 在加载main 方法之前 需要先加载这个类
所以在不实例化这个对象之前的结果是
静态代码块
test构造方法
Process finished with exit code 0
加载顺序: 加载类 --> 静态变量、静态代码块(先后顺序加载) --> 成员变量、一般代码块 --> 构造方法
加载顺序: 加载类 --> 静态变量、静态代码块(先后顺序加载) --> 成员变量、普通代码块 --> 构造方法
再来个栗子
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(2);
}
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(2)
Process finished with exit code 0
**/
父子类初始化顺序
多个类 其实也差不多,顺序如下:
父类静态变量、静态代码块 --> 子类静态变量、静态代码块 --> 父类成员变量、普通代码块--> 父类构造方法 --> 子类成员变量、普通代码块--> 子类构造方法
栗子来了
/*子类*/
public class Child extends Parent {
static {
System.out.println("子类静态代码块");
}
static TestChild test = new TestChild();
{
System.out.println("子类代码块1");
}
String s = "子类成员变量";
{
System.out.println("子类代码块2");
}
Child() {
System.out.println("子类构造器" + s);
}
public static void main(String[] args) {
Parent c = new Child();
}
}
class TestChild {
TestChild (){
System.out.println("用于测试子类静态变量顺序");
}
}
/*父类*/
package com.windy.testBook.five;
/**
* @Author windy
* @Desp
* @Date 2019-03-23 17:13
*/
public class Parent {
static TestParent test = new TestParent();
static {
System.out.println("父类静态代码块");
}
Parent () {
System.out.println("父类构造器" + s);
}
{
System.out.println("父类代码块1");
}
String s = "父类成员变量";
{
System.out.println("父类代码块2");
}
}
class TestParent {
TestParent (){
System.out.println("用于测试父类静态变量顺序");
}
}
/*结果
用于测试父类静态变量顺序
父类静态代码块
子类静态代码块
用于测试子类静态变量顺序
父类代码块1
父类代码块2
父类构造器父类成员变量
子类代码块1
子类代码块2
子类构造器子类成员变量
Process finished with exit code 0
*/
静态代码块或者静态变量是对象加载的时候进行的 只加载一次。如上面所有 只有一个存储区域。而成员变量或者普通代码块 每次实例的时候 都会执行一次 而且都优先于构造方法
网友评论