当前位置:首页 > 后端开发 > 哥们,你真以为你会做这道JVM面试题?

哥们,你真以为你会做这道JVM面试题?

7个月前 (05-24)67

前言

有关Java虚拟机类加载机制相关的文章一搜一大把,我这里也不必再赘述一遍了。

我这里捞出一道code题要各位大佬来把玩把玩,如果你一眼就看出了端倪,那么恭喜你,你可以下山了:


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;
}

问题:请问这段程序的输出是什么?

一般对于这类问题,小伙伴们脑海中肯定浮现出这样的知识点:

Java中赋值顺序:
父类的静态变量赋值
自身的静态变量赋值
父类成员变量赋值和父类块赋值
父类构造函数赋值
自身成员变量赋值和自身块赋值
自身构造函数赋值

按照这个理论输出是什么呢?答案输出:1 4,这样正确嚒?

肯定不正确啦,这里不是说上面的规则不正确,而是说不能简单的套用这个规则。

正确的答案是

2
3
a=110,b=0
1
4

有没有答对呢?这里主要的点之一:实例初始化不一定要在类初始化结束之后才开始初始化

类的生命周期是:加载->验证->准备->解析->初始化->使用->卸载

只有在准备阶段和初始化阶段才会涉及类变量的初始化和赋值,因此只针对这两个阶段进行分析;

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

需要注意的是如果类变量是final,编译时javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将变量设置为指定的值。

如果这里这么定义:static final int b=112,那么在准备阶段b的值就是112,而不再是0了。

类的初始化阶段需要做的是执行类构造器

类构造器是编译器收集所有静态语句块和类变量的赋值语句,按语句在源码中的顺序合并生成类构造器,对象的构造方法是(),类的构造方法是(),可以在堆栈信息中看到。

因此,先执行第一条静态变量的赋值语句,即st = new StaticTest (),此时会进行对象的初始化。

对象的初始化是先初始化成员变量,再执行构造方法。因此打印2->设置a为110->执行构造方法(打印3,此时a已经赋值为110,但是b只是设置了默认值0,并未完成赋值动作)。

等对象的初始化完成后,继续执行之前的类构造器的语句。接下来就不详细说了,按照语句在源码中的顺序执行即可。

这里面还牵涉到一个冷知识,就是在嵌套初始化时有一个特别的逻辑。特别是内嵌的这个变量恰好是个静态成员,而且是本类的实例。

这会导致一个有趣的现象:“实例初始化竟然出现在静态初始化之前”。

其实并没有提前,你要知道java记录初始化与否的时机。看一个简化的代码,把关键问题解释清楚:

public class Test {
   public static void main(String[] args) {
       func();
   }
   static Test st = new Test();
   static void func(){}
}

根据上面的代码,有以下步骤

1、在执行此段代码时,首先由main方法的调用触发静态初始化。

2、在初始化Test 类的静态部分时,遇到st这个成员。

3、但凑巧这个变量引用的是本类的实例。
4、那么问题来了,此时静态初始化过程还没完成就要初始化实例部分了。是这样么?

5、从人的角度是的。但从java的角度,一旦开始初始化静态部分,无论是否完成,后续都不会再重新触发静态初始化流程了。

6、因此在实例化st变量时,实际上是把实例初始化嵌入到了静态初始化流程中,并且在楼主的问题中,嵌入到了静态初始化的起始位置。这就导致了实例初始化完全至于静态初始化之前。这也是导致a有值b没值的原因。

7、最后再考虑到文本顺序,结果就显而易见了。

相信看到这里,心中大概有个结论了吧

关注微信公众号【秃头哥编程】,领取编程大礼包。

在这里插入图片描述

作者:CodeTiger
来源链接:https://www.cnblogs.com/codetiger/p/14876883.html

标签: JVM面试

“哥们,你真以为你会做这道JVM面试题?” 的相关文章

快速带你分清java内存结构,java内存模型,java对象模型和jvm内存结构!

快速带你分清java内存结构,java内存模型,java对象模型和jvm内存结构!

现如今你是否有这样的感觉,无论生活还是学习,节奏都是非常的快,每天面对海量的知识信息,自己感觉都要hold不住了,每天打开微信公众号,是不是发现有几十条未读,无...

prometheus(jvm

prometheus(jvm

下载解压kafka_2.11-0.11.0.2.tgz 1.下载kafka,链接 https://kafka.apache.org/downloads; 2.配置...

java自动化测试面试题

1、为什么做自动化? 解放手工劳动-UI回归测试 持续集成中自动验证 手工测试无法实现-压力 并发测试 2、分层自动化测试?概念应用...

用O(1)的时间复杂度删除单链表中的某个节点

用O(1)的时间复杂度删除单链表中的某个节点

给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下: struct ListNode { int m_nKey;...

java jvm dump文件

java jvm dump文件

JVM 的线程堆栈 dump 也称 core dump,内容为文本,主要包含当时 JVM 的线程堆栈,堆 dump 也称 heap dump,内容为二进制格式,主要...

Java面试题_第二阶段(Servlet、HTTP、Session、JSP、 Ajax、Filter、JDBC、Mysql、Spring)

Java面试题_第二阶段(Servlet、HTTP、Session、JSP、 Ajax、Filter、JDBC、Mysql、Spring)

1.1. 描述Servlet调用过程? 答案: (1)在浏览器输入地址,浏览器先去查找hosts文件,将主机名翻译为ip地址,如果找不到就再去查询dns服务器将主机...

2020年大厂Java面试题集锦,干货集锦,快来集合了!

2020年大厂Java面试题集锦,干货集锦,快来集合了!

       或许这份面试题还不足以囊括所有 Java 问题,但有了它,我相信你一定不会“败”的很惨,因为有了它,足以应对目前市面上绝大部分的 J...

【PHP面试题】PHP如何解决网站大流量与高并发的问题?

文章目录 1、高并发架构相关概念...

[python]面试题:交换两数且不使用临时变量

怎么交换两个数且不使用临时变量? py特有方法 a,b = b,a 异或 a ^= b b ^= a...

【每日打卡】深圳35家公司JAVA面试真题-数据库篇(二)

【每日打卡】深圳35家公司JAVA面试真题-数据库篇(二)

一: 前言 秋招将至,特意整理了之前面试过的题目分...