美文网首页
深入了解Java程序执行顺序

深入了解Java程序执行顺序

作者: 我的轩辕 | 来源:发表于2017-04-11 16:24 被阅读170次

首先做个测试:

public class Test1 {
public static String name;
    public static String name=get();
    public Test1() {
    }
    public static String get() {
        System.out.println("Test start");
        return "test name";
    }
    public static void main(String[] args) {
        System.out.println("main start");
        Text bb = new Text();
    }
}

答案是啥?

main start
test start

那你就out啦

正确答案是:

test start
main start

什么?不是从main方法执行的吗?怎么回事呢?

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

分析:

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

当找到main方法后,因为main方法虽然是一个特殊的静态方法,但是还是静态方法,此时JVM会加载main方法所在的类,试图找到类中其他静态部分,即首先会找main方法所在的类,然后会按照顺序执行类中的静态代码,包括静态变量,静态方法和静态代码块,静态方法在不会主动调用,但会加载。静态方法执行完之后,才是动态代码的执行,包括动态属性赋值和代码块

执行顺序大致分类:

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

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

3.构造方法。

1.1 静态:

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

1.2 普通:

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

现在是否有些理解了呢?

我们再来分析下刚开始的测试题:

1、首先jvm找到main入口,加载整个类
2、找到整个类所有的静态部分,包括静态变量和静态代码块,静态方法,这里是先找到name,发现它调用了get()方法,就先执行get方法,打印 test start ,返回值给name,执行完成之后,发现没有其他的静态变量或代码块啦,就执行main方法,打印main start

再来道测试题:

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();
    }
}

运行结果:

A print
Test print
main start
A的构造方法
Test1的构造方法

如果存在继承关系,会先执行父类的静态部分,再执行子类的静态部分,再执行父类的动态部分,再执行子类的动态部分

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

最后再来一道终极测试题,这是阿里曾经的测试题

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");
    }
}

有没有生无可恋????

运行结果:

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

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

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

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

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

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

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

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

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

然后父类构造方法

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

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

然后子类构造方法

注意:

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

简要分析:

1、首先执行静态部分,先赋值k=0
2、赋值 t1,发现t1涉及到实例化过程,先断开类加载,执行实例化过程
3、实例化过程中,执行类的动态部分,就是j的赋值,它执行了print方法,所以先打印j ,i和n都会先初始化为0
4、j赋值完成之后,继续执行动态部分,就是类的代码块,打印 print("构造块")
5、执行完成后,没动态块之后再执行构造函数,至此整个实例化过程执行完毕,t1赋值完成
6、t2按照t1执行
7、然后赋值 i,n
8、然后再执行静态块,执行 print("静态块"),至此整个类加载过程完成
9、执行main函数,赋值t,t和t1、t2的执行是一样的

相关文章

  • java程序执行顺序

    Java 类中代码的执行顺序深入了解Java程序执行顺序 单个类: static变量—>Static代码块—> m...

  • 深入了解Java程序执行顺序

    首先做个测试: 答案是啥? 那你就out啦 正确答案是: 什么?不是从main方法执行的吗?怎么回事呢? Java...

  • Java程序执行顺序

    执行顺序大致分类: 静态属性,静态方法声明,静态块。 动态属性,普通方法声明,构造块。 构造方法。 详细介绍: 类...

  • Java Script 程序结构(顺序、分支、循环)

    Java Script 程序结构有三种:(顺序结构、分支结构、循环结构) 一、顺序结构:从上到下执行代码,程序默认...

  • 前程科技:JavaSE系列课程之Java程序结构

    Java程序结构 1、顺序结构 按照代码编写顺序,自上而下、逐行执行 2、选择结构 有条件的执行代码,所写的代码在...

  • 安卓面试概要点

    Java基础 访问修饰符 √ 类加载深入理解Java类加载器ClassLoaderJava中类加载的执行顺序 泛型...

  • 第二章 进程的描述与控制

    第二章 进程的描述与控制 前趋图和程序执行 程序的顺序执行 单道程序设计 -> 程序的顺序执行 在程序顺序执行时,...

  • JAVA 线程

    【JAVA 线程】 线程 进程:是一个正在执行中的程序。每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者...

  • Java学习路径

    1.深入了解JVM/JRE/JDK "JVM是Java程序唯一认识的操作系统,其可执行文件为.class" JVM...

  • Day02 逻辑分支

    程序的三大结构(了解) 顺序结构:上下,左右,内外,如果上面报错,下面不执行,终止程序执行。 选择结构:出现分支选...

网友评论

      本文标题:深入了解Java程序执行顺序

      本文链接:https://www.haomeiwen.com/subject/yxfuattx.html