java 中的静态变量,静态代码块,动态代码块,构造方法执行顺序的深入探究

原文:https://blog.csdn.net/qq_41063182/article/details/81149798

类加载:第一次调用这个类的时候jvm虚拟机会通过类加载器在一个叫做方法区的逻辑内存中将所要用到的类的信息存放在里边,其中方法区有一个静态区,存放的是类中的静态(类变量)。

对象构造:在堆中开辟一个内存空间将实例化的对象存放在里边,在生命周期中要远远小于类。

静态代码块只有在类加载时仅且执行一次

动态代码块是在每次构造对象时执行一次,然后才是构造方法,也就有了一个顺序。

静态代码块>动态代码块>构造方法,而静态变量与静态代码块的优先级是一个级别的,这样看来好像问题解决了,但其实问题并不是这么简单。

看一个阿里面试题

public class Test {
    public static int k = 0;
    public static Test t1 = new Test("t1");
    public static Test t2 = new Test("t2");
    public static int i = print("i");
    public static int n = 99;
    private int a = 0;
    public int j = print("j");
    
    {
        print("构造块");
    }
 
    static {
        print("静态块");
    }
 
    public Test(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[]) {
        Test t = new Test("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

顺序不对:先执行的非静态的赋值变量,然后动态代码块,然后构造方法,静态代码块一次都没有执行,一直等到第八次才执行出来。那么问题就来了,java中不是说静态代码块是在类加载时便执行一次,可是这里为什么不执行。

在看一段代码

package com.basics.day10;
 
public class TestStatic {
    
    
    static {
        System.out.println("这时TestStatic的静态代码块!");
    }
    
    {
        System.out.println("这是动态代码块!");
    }
    public TestStatic() {
        System.out.println("这是构造代码块");
    }
    
    public static void main(String[] args) {
        TestStatic te = new TestStatic();
        TestStatic t2 = new TestStatic();
    }
    
}
// 请注意看这个类中的静态代码块
class Annoy {
    static {
        System.out.println("Annoy的静态代码块");
    }
}

结果:


这时TestStatic的静态代码块!
这是动态代码块!
这是构造代码块
这是动态代码块!
这是构造代码块

主类中并没有引用Annoy类,也就是这个类并没有被加载进方法区,既然它没有被加载,那么其中的代码块自然就不会执行了。

类的加载只有在引用它的时候才会加载,而不是直接加载进方法区的,这也是类加载与构造对象的区别。构造对象并不是类加载,它们是两个完全不一样的概念,类加载要在对象构造之前。

折回到阿里巴巴的那道题中,发现他在第二行的时候进行了对象的构造,而在这个构造中执行的都是非静态的代码块。我是这样理解的,在这个类的main函数被jvm识别的时候,这个类已经加载到方法区中去了,这时候静态都会被执行一次,而且是按照声明的顺序执行的,正常下来,先k,t1,t2...跳过j,到静态代码块,但这里t1有了一个变故,那就是他构造了一个对象,这时类已经加载完成,相当于静态已经默认被执行了一次,只是顺序上还没有轮到,根据静态的特性,他只执行一次,所以t1这里的分支,调用的就是动态代码块以及构造方法,不会去管那些静态,这也就导致出现了上边的那种情况。

你可能感兴趣的:(java小知识点)