java 执行顺序混乱_深入了解Java程序执行顺序(转载)

Java中main方法,静态,非静态的执行顺序详解

Java程序运行时,第一件事情就是试图访问main方法,因为main相等于程序的入口,如果没有main方法,程序将无法启动,main方法更是占一个独立的线程,找到main方法后,是不是就会执行mian方法块里的第一句话呢?答案是不一定

看看下面两种最常见的情况:

第一种情况:

main方法在一个具有其他方法或属性的类中;

48304ba5e6f9fe08f3fa1abda7d326ab.png

public class Test1 {

public static String name;

public Test1() {

}

public static void get() {

System.out.println("Test start");

}

public static void main(String[] args) {

System.out.println("main start");

Test1 bb = new Test1();

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

第二种情况:

main方法在一个没有其他方法或属性的类中;

public class Test {

public static void main(String[] args) {

Student stu =new Student();

}

}

分析:

因为静态部分是依赖于类,而不是依赖于对象存在的,所以静态部分的加载优先于对象存在。

当找到main方法后,因为main方法虽然是一个特殊的静态方法,但是还是静态方法,此时JVM会加载main方法所在的类,试图找到类中其他静态部分,即首先会找main方法所在的类。

执行顺序大致分类:

1.静态属性,静态方法声明,静态块。

2.动态属性,普通方法声明,构造块。

3.构造方法。

1.1 静态:

当加载一个类时,JVM会根据属性的数据类型第一时间赋默认值(一举生成的)。然后再进行静态属性初始化,并为静态属性分配内存空间,静态方法的声明,静态块的加载,没有优先级之分,按出现顺序执行,静态部分仅仅加载一次。至此为止,必要的类都已经加载完毕,对象就可以被创建了。

1.2 普通:

当new一个对象时,此时会调用构造方法,但是在调用构造方法之前,(此刻1.1已经完成,除非被打断而暂停)执行动态属性定义并设置默认值(一举生成的)。然后动态属性初始化,分配内存,构造块,普通方法声明(只是加载,它不需要初始化,只有调用它时才分配内存,当方法执行完毕后内存立即释放),没有优先级之分,按出现顺序执行。最后进行构造方法中赋值。当再次创建一个对象,不再执行静态部分,仅仅重复执行普通部分。

注意:如果存在继承关系,创建对象时,依然会首先进行动态属性进行定义并设默认值,然后父类的构造器才会被调用,其他一切都是先父类再子类(因为子类的static初始化可能会依赖于父类成员能否被正确初始化),如果父类还有父类,依次类推,不管你是否打算产生一个该父类的对象,这都是自然发生的。

下面是一道小程序:

代码部分:

48304ba5e6f9fe08f3fa1abda7d326ab.png

class A {

public A() {

System.out.println("A的构造方法");

}

public static int j = print();

public static int print() {

System.out.println("A print");

return 521;

}

}

public class Test1 extends A {

public Test1() {

System.out.println("Test1的构造方法");

}

public static int k = print();

public static int print() {

System.out.println("Test print");

return 522;

}

public static void main(String[] args) {

System.out.println("main start");

Test1 t1 = new Test1();

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

运行结果:

A print

Test print

main start

A的构造方法

Test1的构造方法

下面是一道阿里巴巴的面试题:非常经典,可以不断的改变程序的顺序,来找到执行顺序机制。

代码部分:

48304ba5e6f9fe08f3fa1abda7d326ab.png

public class Text {

public static int k = 0;

public static Text t1 = new Text("t1");

public static Text t2 = new Text("t2");

public static int i = print("i");

public static int n = 99;

public int j = print("j");

{

print("构造块");

}

static {

print("静态块");

}

public Text(String str) {

System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);

++i;

++n;

}

public static int print(String str) {

System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);

++n;

return ++i;

}

public static void main(String args[]) {

Text t = new Text("init");

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

运行结果:

48304ba5e6f9fe08f3fa1abda7d326ab.png

1:j i=0 n=0

2:构造块 i=1 n=1

3:t1 i=2 n=2

4:j i=3 n=3

5:构造块 i=4 n=4

6:t2 i=5 n=5

7:i i=6 n=6

8:静态块 i=7 n=99

9:j i=8 n=100

10:构造块 i=9 n=101

11:init i=10 n=102

48304ba5e6f9fe08f3fa1abda7d326ab.png

总结:只要按照这个步骤,遇到这一类问题就可以解决了。

1-3:类加载过程,不涉及构造方法

1-5: 实例化过程,涉及构造方法

1.类中所有属性的默认值(一举而成)

2. 父类静态属性初始化,静态块,静态方法的声明(按出现顺序执行)

3. 子类静态属性初始化,静态块,静态方法的声明 (按出现顺序执行)

4.  调用父类的构造方法,

首先父类的非静态成员初始化,构造块,普通方法的声明(按出现顺序执行)

然后父类构造方法

5.  调用子类的构造方法,

首先子类的非静态成员初始化,构造块,普通方法的声明(按出现顺序执行)

然后子类构造方法

(注意:类加载过程中,可能调用了实例化过程(因为static可以修饰方法,属性,代码块,内部类),此时则会暂停类加载过程而先执行实例化过程(被打断),执行结束再进行类加载过程,上面阿里那道面试题就是典型的暂停类加载。

下面附加一个小程序来显示新建对象时属性的四个过程:

48304ba5e6f9fe08f3fa1abda7d326ab.png

public class Test {

public static void main(String[] args) {

Student stu = new Student("zhangan", 21);

}

}

class Student {

public String name = "李寻欢";

public int age = 20;

public Student(String name, int age) {

this.name = name;

this.age = age;

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

1.

e5cdbb5340b0510ab70c7d29c0d54ee0.png

2.

d9bc8cd29ee128ac71db24f489f1e5fe.png

3.

3db09d63fed306cb436b58997879a2b8.png

4.

e6a32d757298fa7dae69a402cb43e38f.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值