• 看起来很懵的java内存加载面试题


    源代码如下,求结果

    public class MemoryAnalyse {
        public static int k = 0;
        public static MemoryAnalyse t1 = new MemoryAnalyse("t1");
        public static MemoryAnalyse t2 = new MemoryAnalyse("t2");
        public static int i = print("i");
        public static int j = print("j");
        public static int n = 99;
        
        {
            print("constructor code");
        }
        
        static {
            print("static code");
        }
    
        public static int print(String s) {
            System.out.println("i=" + i + "   " + s + "  k=" + k + "  n=" + n
                    + "   j=" + j);
            ++i;
            ++k;
            ++n;
            return i;
        }
    
        public MemoryAnalyse(String string) {
            print(string);
        }
    
        public static void main(String[] args) throws ClassNotFoundException {
            MemoryAnalyse d = new MemoryAnalyse("T");
        }
    }

    源码下载

    然而结果是这个

    i=0   constructor code  k=0  n=0   j=0
    i=1   t1  k=1  n=1   j=0
    i=2   constructor code  k=2  n=2   j=0
    i=3   t2  k=3  n=3   j=0
    i=4   i  k=4  n=4   j=0
    i=5   j  k=5  n=5   j=0
    i=6   static code  k=6  n=99   j=6
    i=7   constructor code  k=7  n=100   j=6
    i=8   T  k=8  n=101   j=6

    有没有很惊讶,结果竟然这么复杂.好,下面我们分析一下,在分析之前,先普及下不怎么用的基础知识

    代码块和静态代码块何时运行问题:

      代码块在创建对象时运行
      静态代码块在类加载时运行

    大家都知道static是属于类的并非对象,也就是说static修饰的东西都会在class加载到方法区时就存在在那里.所以方法区中类加载时内存过程如下

    1.当类刚加载时会全部加载到方法区时,此时所有变量全部未实例化.

    2.实例化参数t1

    此时因为代码块在创建对象时执行,且在构造函数之前执行,所以先执行代码块

    {
    print("constructor code");
    }

      因为此时所有的变量都为默认值,所以执行后打印结果为

    i=0   constructor code  k=0  n=0   j=0

    此时i,n,k的值都已经自加一,值为1

    然后实例化调用构造函数

    public MemoryAnalyse(String string) {   //这里string为t1
            print(string);
    }

      构造函数调用结果如下

      i=1   t1  k=1  n=1   j=0
      此时i,n,k的值都已经自加一,值为2

    3.实例化参数t2

    和第一步一样在构造函数之前执行代码块

    {
    print("constructor code");
    }

    i=2   constructor code  k=2  n=2   j=0

    此时i,n,k的值都已经自加一,值为3

    然后实例化调用构造函数

    public MemoryAnalyse(String string) {   //这里string为t2
            print(string);
    }

      构造函数调用结果如下

    i=3   t2  k=3  n=3   j=0

    此时i,n,k的值都已经自加一,值为4

    4.初始化参数i

      这里直接调用print("i")函数,得到结果为

      i=4   i  k=4  n=4   j=0

      此时i,k,j值为5,注意i的值不是通过自加一变成5的,而是通过函数的返回值赋给i的

      5.初始化参数j

      

      这里和上一步一样,执行print("j"),然后把函数的返回值赋给j,打印结果为

      i=5   j  k=5  n=5   j=0

      此时j的值已经为6

    到这里类加载的内部参数变化就完成了,我们可以用加载类的方式调用一下

        public static void main(String[] args) throws ClassNotFoundException {
            //MemoryAnalyse d = new MemoryAnalyse("T");
            Class.forName("MemoryAnalyse");
        }

    Class.forName(类名字符串)是手动加载类到方法区,得到结果为

    i=0   constructor code  k=0  n=0   j=0
    i=1   t1  k=1  n=1   j=0
    i=2   constructor code  k=2  n=2   j=0
    i=3   t2  k=3  n=3   j=0
    i=4   i  k=4  n=4   j=0
    i=5   j  k=5  n=5   j=0
    i=6   static code  k=6  n=99   j=6  //这行的出现是因为static代码段在类加载时执行.n=99是因为类加载了,n的初值为99把之前的值覆盖掉了

    然后改为我们之前的demo

    public static void main(String[] args) throws ClassNotFoundException {
            MemoryAnalyse d = new MemoryAnalyse("T");
            //Class.forName("MemoryAnalyse");
        }

    执行结果为

    i=0   constructor code  k=0  n=0   j=0    //t1代码块执行
    i=1   t1  k=1  n=1   j=0  //t1构造函数执行
    i=2   constructor code  k=2  n=2   j=0   //t2代码块执行
    i=3   t2  k=3  n=3   j=0  //t2构造函数执行
    i=4   i  k=4  n=4   j=0
    i=5   j  k=5  n=5   j=0
    i=6   static code  k=6  n=99   j=6  //静态代码块执行
    i=7   constructor code  k=7  n=100   j=6    //T代码块执行
    i=8   T  k=8  n=101   j=6     //T构造函数执行

    最后两行的出现就很简单了,一个是代码块的,一个是构造函数的

    这么一分析是不是简单了很多

  • 相关阅读:
    ng机器学习视频笔记(八) ——机器学习系统调试(cv、查准率与召回率等)
    ng机器学习视频笔记(七) ——神经网络的代价函数、反向传播、梯度检验、随机初始化
    post body 传输参数
    laravel队列使用
    nginx配置框架问题
    中大型网站架构之路一
    mongo笔记2
    架构4(lvs lb集群解决方案二 lvs+keepalived)
    架构3(基于LVS LB集群解决方案一:piranha)
    YII2 BUG记录
  • 原文地址:https://www.cnblogs.com/aeolian/p/7857664.html
Copyright © 2020-2023  润新知