zoukankan      html  css  js  c++  java
  • 讨论下类加载的顺序问题

    我们先看一个例子:

    class A3{
        B3 b3 = new B3();
        static C3 c4 = new C3();
        static{
            System.out.println("A3");
        }
      public A3() {
      System.out.println("A3-init");
      }
    } 

      

    class B3{ static{ System.out.println("B3"); } } 
    class C3{ static{ System.out.println("C3"); } } 
    public class StaticTest { 
      public static void main(String[] args) 
        { 
          A3 a3 = new A3(); 
        } 
      }

      现在看一下A3的字节码 clinit

     0 new #5 <com/suning/mxz/TestJVM/C3>   静态成员变量先初始化,也说明了会先load这个class
     3 dup
     4 invokespecial #6 <com/suning/mxz/TestJVM/C3.<init>>
     7 putstatic #7 <com/suning/mxz/TestJVM/A3.c4>
    10 getstatic #8 <java/lang/System.out>
    13 ldc #9 <A3>
    15 invokevirtual #10 <java/io/PrintStream.println>
    18 return
    

      init

    0 aload_0
    1 invokespecial #1 <java/lang/Object.<init>>
    4 aload_0
    5 new #2 <com/suning/mxz/TestJVM/B3>
    8 dup
    9 invokespecial #3 <com/suning/mxz/TestJVM/B3.<init>>
    12 putfield #4 <com/suning/mxz/TestJVM/A3.b3>
    15 getstatic #5 <java/lang/System.out>
    18 ldc #6 <A3-init>
    20 invokevirtual #7 <java/io/PrintStream.println>
    23 return

      从上面可以看出来,在A3的初始化字节码里首先是执行Object的构造方法,然后才是成员变量的构造方法,最后才是自己的构造方法里的逻辑

    ==============================2020-12-25=====================

      1  类加载的最后一步是初始化,这里说的初始化是指clinit,注意可不是执行实例变量的构造方法,clinit所做的就是执行static代码块和static的变量。所以,能看到clinit的字节码就干了两件事。一个是new一个C3并赋值给c4这个引用。一个是执行static代码块

      2 然后是当执行main方法中的  A3 a3 = new A3();  

      此时的init方法字节码的顺序是

      1 执行Object的init,注意这个init是字节码的init,可不是直接的Object的构造方法

      2 初始化成员变量,这里是b3

      3 然后执行A3的构造方法

      注意观察B3的执行可以总结如下

    4 aload_0
    5 new #2 <com/suning/mxz/TestJVM/B3> new
    8 dup
    9 invokespecial #3 <com/suning/mxz/TestJVM/B3.<init>> 执行init
    12 putfield #4 <com/suning/mxz/TestJVM/A3.b3> 赋值

      1 new 分配空间

      2 执行字节码里的init

      3 把对象的地址赋值给引用

      在这里也可以看得出来,当new一个对象的时候,不单单是执行构造方法。字节码里的init的范围是比我们写的构造方法要大的。因为还要初始化成员变量。

      在这里再抛出来一个问题,成员变量如果没有初始化字节码是怎么样的

    public class Account {
        private int id ;
    0 aload_0
    1 invokespecial #1 <java/lang/Object.<init>>
    4 return

      能够看得出来,没有对id做任何的操作。而且代码中没有写构造方法,所以在这里直接执行Object的init之后就返回了

      

      

      

  • 相关阅读:
    ASP.NET MVC 5 学习教程:使用 SQL Server LocalDB
    ASP.NET MVC 5 学习教程:生成的代码详解
    ASP.NET MVC 5 学习教程:通过控制器访问模型的数据
    ASP.NET MVC 5 学习教程:创建连接字符串
    ASP.NET MVC 5 学习教程:添加模型
    ASP.NET MVC 5 学习教程:控制器传递数据给视图
    ASP.NET MVC 5 学习教程:修改视图和布局页
    ASP.NET MVC 5 学习教程:添加视图
    ASP.NET MVC 5 学习教程:添加控制器
    ASP.NET MVC 5 学习教程:快速入门
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13527778.html
Copyright © 2011-2022 走看看