一、初始化顺序
在类的内部,变量的定义顺序先后决定了初始化的顺序。即使变量定义在不同的方法之间,它们也会在任何方法(包括构造函数)在调用之前初始化。
1.简单的初始化顺序:
class Sample {
Sample() {
System.out.println("Sample默认构造函数被调用");
}
Sample(String s) {
System.out.println(s);
}
}
public class JavaInit {
Sample sam1 = new Sample("sam1成员初始化");
JavaInit() {
System.out.println("JavaInit默认构造函数被调用");
}
Sample sam2 = new Sample("sam2成员初始化");
void print() {
System.out.println("print()");
}
public static void main(String[] args) {
JavaInit ji = new JavaInit();
ji.print();
}
}
输出:
sam1成员初始化
sam2成员初始化
JavaInit默认构造函数被调用
print()
2、静态数据初始化:
public class JavaStaticInit {
static Sample sam = new Sample("静态成员sam初始化");
Sample sam1 = new Sample("sam1成员初始化");
JavaStaticInit() {
System.out.println("JavaStaticInit默认构造函数被调用");
}
public static void main(String str[]) {
JavaStaticInit a = new JavaStaticInit();
JavaStaticInit a1 = new JavaStaticInit();
}
输出:
静态成员sam初始化
sam1成员初始化
JavaStaticInit默认构造函数被调用
sam1成员初始化
JavaStaticInit默认构造函数被调用
由输出结果可以看到:只有在第一个JavaStaticInit对象被创建(或第一次的访问静态数据)的时候,它们才会被初始化,此后,静态对象不会被再次初始化。
3、静态块的初始化:
public class JavaStaticInit {
static {
System.out.println("static 块 1 执行");
}
static Sample sam = new Sample("静态成员sam初始化");
Sample sam1 = new Sample("sam1成员初始化");
JavaStaticInit() {
System.out.println("JavaStaticInit默认构造函数被调用");
}
static {
System.out.println("static块执行");
Sample sam2 = new Sample("静态块内初始化sam成员变量");
}
public static void main(String str[]) {
JavaStaticInit a = new JavaStaticInit();
JavaStaticInit a1 = new JavaStaticInit();
}
输出:
static 块 1 执行
静态成员sam初始化
static块执行
静态块内初始化sam成员变量
sam1成员初始化
JavaStaticInit默认构造函数被调用
sam1成员初始化
JavaStaticInit默认构造函数被调用
由此而知,对于静态成员(static块可以看成普通的一个静态成员,其并不一定在类初始化时首先执行)之间或者普通成员之间,其初始化顺序只与其在类定义中的顺序有关,和其他因素无关。
4.非静态实例初始化:
class Mug {
Mug(int mark) {
System.out.println("Mug(" + mark + ")");
}
}
public class Mugs {
Mug mug1;
Mug mug2;
Mug mug3;
Mug mug4;
{
mug1 = new Mug(1);
mug2 = new Mug(2);
System.out.println("mug1---------------------mug2");
}
Mugs() {
System.out.println("Mugs()");
}
Mugs(int mark) {
System.out.println("Mugs(" + mark + ")");
}
{
mug3 = new Mug(3);
mug4 = new Mug(4);
System.out.println("mug3---------------------mug4");
}
public static void main(String[] args) {
new Mugs();
new Mugs();
}
}
输出:
Mug(1)
Mug(2)
mug1———————mug2
Mug(3)
Mug(4)
mug3———————mug4
Mugs()
Mug(1)
Mug(2)
mug1———————mug2
Mug(3)
Mug(4)
mug3———————mug4
Mugs()
二、继承下的初始化
class A {
public static int a = 0;
public int b = 0;
Sample sam1 = new Sample("■父类 -普通变量-位置是构造函数前");
static {
System.out.println("■父类 - 静态初始块 - 位置是构造函数前");
}
{
System.out.println("■父类 - 普通初始块 - 位置是构造函数前");
}
public A() {
System.out.println("■父类 - 构造函数");
}
static {
System.out.println("■父类 - 静态初始块 - 位置是构造函数后");
}
{
System.out.println("■父类 - 普通初始块 - 位置是构造函数后");
}
Sample sam2 = new Sample("■父类 -普通变量-位置是构造函数后");
}
class B extends A {
Sample sam1 = new Sample(“◆子类 -普通变量-位置是构造函数后”);
static {
System.out.println(“◆子类 - 静态初始块 - 位置是构造函数前”);
}
{
System.out.println(“◆子类 - 普通初始块 - 位置是构造函数前”);
}
public B() {
System.out.println(“◆子类 - 构造函数”);
}
static {
System.out.println(“◆子类 - 静态初始块 - 位置是构造函数后”);
}
{
System.out.println(“◆子类 - 普通初始块 - 位置是构造函数后”);
}
Sample sam2 = new Sample(“◆子类 -普通变量-位置是构造函数后”);
}
public class MS_Extends {
public static void main(String[] args) {
B b = new B();
}
}
输出:
■父类 - 静态初始块 - 位置是构造函数前
■父类 - 静态初始块 - 位置是构造函数后
◆子类 - 静态初始块 - 位置是构造函数前
◆子类 - 静态初始块 - 位置是构造函数后
■父类 -普通变量-位置是构造函数前
■父类 - 普通初始块 - 位置是构造函数前
■父类 - 普通初始块 - 位置是构造函数后
■父类 -普通变量-位置是构造函数后
■父类 - 构造函数
◆子类 -普通变量-位置是构造函数后
◆子类 - 普通初始块 - 位置是构造函数前
◆子类 - 普通初始块 - 位置是构造函数后
◆子类 -普通变量-位置是构造函数后
◆子类 - 构造函数
由此可知,
1、按照顺序执行父类静态变量、静态块
2、按照顺序执行子类静态变量、静态块
3、按照顺序执行父类的普通变量、普通块、执行父类的构造函数
4、按照顺序执行子类的普通变量、普通块、执行子类的构造函数
三、总结:
1、 继承体系的所有静态成员初始化(先父类,后子类)
2、 父类初始化(普通成员的初始化–>构造函数的调用)
3 、子类初始化(普通成员–>构造函数)
##一、
小知识点总结:
static{}(静态代码块)与{}(非静态代码块)的异同点
相同点:都是在JVM加载类时且在构造方法执行之前执行,在类中都可以定义多个,
一般在代码块中对一些static变量进行赋值。
不同点:静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。
静态代码块只在第一次new执行一次,之后不再执行,而非静态代码块在每new
一次就执行一次。非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行