zoukankan      html  css  js  c++  java
  • 一道有趣的类加载面试题

    题目

    运行如下代码的Test1与Test2分别输出什么结果

    
    public class Parent {
        static {
            System.out.println("Parent static invoke");
        }
        public static final String FINAL_STR="FINAL_STR";
        public static final Test FINAL_OBJECT=new Test();
        public Parent(){
            System.out.println("Parent init");
        }
    }
    public class Child extends Parent {
        static {
            System.out.println("Child static invoke");
        }
        public Child(){
            System.out.println("child init");
        }
    }
    public class Test {
        public static void main(String[] args) {
            System.out.println(Child.FINAL_STR);
        }
    }
    public class Test2 {
        public static void main(String[] args) {
            System.out.println(Child.FINAL_OBJECT);
        }
    }
    
    

    结果:

    运行Test1结果

    FINAL_STR
    

    运行Test2结果

    Parent static invoke
    cn.lonecloud.Test@5e2de80c
    

    解析:

    Test1结果解析:

    1. 由于在mian方法中打印语句调用的是Child.FINAL_STR变量。
    2. 从Child的类中可以得知,FINAL_STR为final并且为static变量,其在调用static final变量的时候不会触发类的初始化操作。所以结果如上

    Test2结果解析:

    1. 由于Test2中引用的对象为父类Parent的静态变量,由于并不是常量池中的对象,所以,会触发Parent的初始化操作。

    深究:

    Test1字节码:

    Compiled from "Test.java"
    public class cn.lonecloud.Test {
      public cn.lonecloud.Test();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc           #4                  // String FINAL_STR
           5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
           8: return
    }
    
    
    1. ldc #4 // String FINAL_STR其为获取静态化变量方法,其为将常量压入栈中,由于静态变量在JVM中存在常量池的概念,会将字符串进行优化,所以并不会触发类初始化

    Test2字节码:

    Compiled from "Test.java"
    public class cn.lonecloud.Test {
      public cn.lonecloud.Test();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           3: getstatic     #3                  // Field cn/lonecloud/Child.FINAL_OBJECT:Lcn/lonecloud/Test;
           6: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
           9: return
    }
    

    由于需要使用到Child类的父类中的FINAL_OBJECT变量,未使用到Child类中的变量,所以不会对Child类进行初始化,初始化的为其父类。

    查看JVM加载情况

    通过添加JVM参数-XX:+TraceClassLoading可以查看类加载情况

    可见,会对Child,Parent类进行类加载操作,但是调用static方法,只有Parent类会调用static进行初始化操作。

    总结

    1. 如果引用了常量池变量(String,以及基本类型相关变量),如果该变量为final static进行修饰的时候,则不会对类进行初始化操作
    2. 如果为非常量池变量,如果调用方存在父子类关系,则实际JVM会加载子类与父类,但是如果使用的为父类的final变量,并不会触发类的初始化操作。
  • 相关阅读:
    HDU 4069 Squiggly Sudoku
    SPOJ 1771 Yet Another NQueen Problem
    POJ 3469 Dual Core CPU
    CF 118E Bertown roads
    URAL 1664 Pipeline Transportation
    POJ 3076 Sudoku
    UVA 10330 Power Transmission
    HDU 1426 Sudoku Killer
    POJ 3074 Sudoku
    HDU 3315 My Brute
  • 原文地址:https://www.cnblogs.com/lonecloud/p/11757316.html
Copyright © 2011-2022 走看看