1_Java类加载机制

  • 类的生命周期是:加载->验证->准备->解析->初始化->使用->卸载,只有在__准备__阶段和__初始化__阶段才会涉及类变量(static)的初始化和赋值,因此只针对这两个阶段进行分析

  • 类的准备阶段需要做的是__为类变量分配内存并设置默认值__,因此类变量st为null、b为0

  • 如果类变量被final修饰,编译时javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将变量设置为指定的值__,如果这里这么定义:static final int b=112,那么在准备阶段b的值就是112,而不再是0了。

  • 类的初始化阶段需要做的是__执行类构造器__(类构造器是编译器__收集所有静态语句块和类变量的赋值语句__按语句__在源码中的顺序__合并生成类构造器,),因此__先执行第一条静态变量的赋值语句即st = new StaticTest (),此时会进行对象的初始化__,对象的初始化是__先初始化成员变量再执行构造方法__,因此设置a为110->打印2->执行构造方法(打印3,此时a已经赋值为110,但是b只是设置了默认值0,并未完成赋值动作),等对象的初始化完成后继续执行之前的类构造器的语句,接下来就不详细说了,按照语句在源码中的顺序执行即可。


public class StaticTest {

    public static void main(String[] args) {
        staticFunction();
    }

    static StaticTest st = new StaticTest();

    static {
        System.out.println("1");
    }

    {
        System.out.println("2");
    }

    StaticTest() {
        System.out.println("3");
        System.out.println("a=" + a + ",b=" + b);
    }

    public static void staticFunction() {
        System.out.println("4");
    }

    int a = 110;
    static int b = 112;

    static final int c = 200;
}

1° 现在, JVM要执行StaticTest类的main方法, 所以要试着加载StaticTest类;

2° 加载StaticTest类之前, 要看看StaticTest是否继承于哪个类, 如果继承的类还没有被加载, 那就先加载父类(这是一个递归加载的过程)。现在StaticTest没继承哪个类,所以加载它自己就行了(其实是先加载了Object类)

3° 准备阶段,为非final变量分配内存并设置默认初始值.此时st为null,b为0,而c由于被final修饰,所以c为200;

4° 接下来初始化阶段,此时执行类构造器将类变量赋值,执行顺序按照源码中出现的顺序(无所谓是块还是语句,一切按照源码顺序),所以先初始化构造st对象;

5° 本例的特殊之处在于st对象属于StaticTest类,因此将对象实例的初始化过程嵌入了类的静态初始化过程。实例初始化构造的顺序是先按源码顺序初始化成员变量和非静态块,再执行构造函数,因此先打印“2”(此时a还是0),再a=110,再执行st对象的构造函数,此时b仍为0;

注: 如果在非静态块中System.out.println(a)怎样办呢?
答: 会报错,不让这么用

6° 刚才第2步只是完成了 st对象的初始化过程,接下来按照顺序继续将静态块执行,所以打印“1”,b赋值为112;

4° 初始化过程结束后,调用staticFunction函数,打印“4”

因此答案为
2
3
a=110,b=0
1
4
  • 内部类不会在类加载的过程中加载,除非真的要用它的静态变量或实例化一个对象(啥时候真正用到它啥时候加载)

    所以,这就诞生了另一种使用静态内部类写单例模式的写法

      public class Singleton {  
      
          private Singleton() {}  
    
          private static class SingletonHolder {
              private static Singleton instance = new Singleton();  
          }
    
          public static Singleton getInstance() {  
              return SingletonHolder.instance;  
          }
      }
    

    解释

    因为内部静态类是要在有引用了以后才会装载到内存的,所以在第一次调用getInstance()之前,SingletonHolder是没有被装载进来的,只有在第一次调用了getInstance()之后,里面涉及到了return SingletonHolder.instance,产生了对SingletonHolder的引用,内部静态类的实例才会真正装载;

    又,虚拟机会保证一个类的()方法在多线程环境下可以被正确的加锁、同步,因此多线程同时初始化一个类的时候,只有一个线程会执行这个类的()方法。同一个类加载器下,一个类型只会初始化一次

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值