类加载过程,吊打面试官,超级干货

发布于:2023-07-04 ⋅ 阅读:(177) ⋅ 点赞:(0)

类加载过程

加载, 验证, 准备, 解析, 初始化下面依次说说

加载阶段

验证

  • 主要是对类元数据等信息结构的校验

准备

  • 对类实例赋零值
    • 注意final static是在编译器编译的时候就应经进入了常量池中,。

解析

  • 解析阶段常量池中的方法的符号引用直接解析成直接引用

  • 解析过程之字段解析(字段查找过程)

    • 该字段的字段表的Constant_Class_info常量指向的类/接口C

      • 在字段查找的时候, 先在本身的类中查找, 如果没有, 从接口中查找(从最先实现开始, 从下往上), 如果接口中没有, 或者没有实现接口, 从继承的父类中查找(从最先实现开始, 从下往上)
      • image-20220623164843459
  • 解析过程之方法解析(方法的查找)

    • 分派

      • 静态分派

        • 非虚方法

          • 在解析阶段中可以事先确定唯一的调用版本有静态方法、私有方法、实例构造器、父类方法4类

          • final方法

          • 一个类的方法重载

            • 重载是根据方法的静态参数类型区分的而不是实例参数, 所以在选中方法的版本的时候也是根据方法的静态参数, 而非实例参数.

              • demo

                • /**
                   * 重载是根据方法的静态参数类型区分的而不是实例参数, 所以在选中方法的版本的时候也是根据方法的静态参数, 而非实例参数.
                   */
                  public class StaticDispatch {
                  
                    static abstract class Human {
                    }
                  
                    static class Man extends Human {
                  
                    }
                  
                    static class Woman extends Human {
                  
                    }
                  
                    public void sayHello(Human guy) {
                  
                      System.out.println("hello,guy!");
                  
                    }
                  
                    public void sayHello(Man guy) {
                  
                      System.out.println("hello,gentleman!");
                  
                    }
                  
                    public void sayHello(Woman guy) {
                  
                      System.out.println("hello,lady!");
                  
                    }
                  
                    public static void main(String[] args) {
                  
                      Human man = new Man();
                  
                      Human woman = new Woman();
                  
                      StaticDispatch sr = new StaticDispatch();
                  
                      sr.sayHello(man);
                  
                      sr.sayHello(woman);
                      //运行结果是:
                      //hello,guy
                      //hello,guy
                  
                    }
                  
                  }
                  
            • 如果实参类型没有直接对应匹配的方法,则实参会向上逐步类型提升,可见变长参数(数组或者…)的重载优先级是最低的, 直到找到方法

              • import java.io.Serializable;
                
                /**
                 * 如果实参类型没有直接对应匹配的方法,则实参会向上逐步类型提升,可见变长参数(数组或者...)的重载优先级是最低的, 直到找到方法
                 */
                
                public class OverloadTest {
                
                //  public static void sayHello(char arg) {
                //
                //    System.out.println("hello char");                                //  |
                //                                                                     //  |
                //  }                                                                  //  |
                                                                                       //  |
                  public static void sayHello(int arg) {
                                                                                       //  |
                    System.out.println("hello int");                                   //  |
                                                                                      //  ╲↓╱
                  }//代码我给排序了,类型自动提升过程 char,int,long,Character,Serializable,Object,char []
                
                  public static void sayHello(long arg) {
                
                    System.out.println("hello long");
                
                  }
                
                  public static void sayHello(Character arg) {
                
                    System.out.println("hello Character");
                
                  }
                
                  public static void sayHello(Serializable arg) {
                    
                    System.out.println("hello Serializable");
                    
                  }
                  
                  public static void sayHello(Object arg) {
                    
                    System.out.println("hello Object");
                    
                  }
                
                  public static void sayHello(char... arg) {
                
                    System.out.println("hello char……");
                
                  }
                
                  public static void main(String[] args) {
                
                    sayHello('a');
                      // 运行结果为hello int
                //代码我给排序了,不要误解为从上往下查找哈,当找不到的情况下,实参会自动类型提示,这个查了类型自动提升过程为 char,int,long,Character,Serializable,Object,char []
                  }
                }
                
                
      • 动态分派

        • 虚方法
          • 指向常量池中的方法的符号引用

初始化

  • 类的加载、验证、准备、初始化是先后开始的, 多是在初始化之前,加载,验证,准备必然是已经开始了。

    初始化阶段(Cinit<>)对static类变量赋初始值(非零值)

  • 初始化的5个时机

    • new / putstatic(调用类的static方法或static字段(非final static)的时候)
    • 子类初始化的时候如果父类没有初始化, 那么父类会初始化
    • main入口方法对应的类
    • 反射
    • …忘记了
  • 3种容易误以为会初始化的情况

    • 子类.父类static 属性
      • 这种情况只会初始化父类, 不会初始化子类
    • 数组元素是类类型,那么这种类类型不会初始化, 除非实例化数组元素
    • 访问类的final static属性。 那么这个类是不会初始化的, 因为final static在编译阶段就会直接保存到常量池中, 如果用到final static属性, 也只是宏替代。
本文含有隐藏内容,请 开通VIP 后查看

微信公众号

今日签到

点亮在社区的每一天
去签到