哥们,你真以为你会做这道JVM面试题?
有关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(){}
}
根据上面的代码,有以下步骤:
- 首先在执行此段代码时,首先由main方法的调用触发静态初始化。
- 在初始化Test 类的静态部分时,遇到st这个成员。
- 但凑巧这个变量引用的是本类的实例。
- 那么问题来了,此时静态初始化过程还没完成就要初始化实例部分了。是这样么?
- 从人的角度是的。但从java的角度,一旦开始初始化静态部分,无论是否完成,后续都不会再重新触发静态初始化流程了。
- 因此在实例化st变量时,实际上是把实例初始化嵌入到了静态初始化流程中,并且在楼主的问题中,嵌入到了静态初始化的起始位置。这就导致了实例初始化完全至于静态初始化之前。这也是导致a有值b没值的原因。
- 最后再考虑到文本顺序,结果就显而易见了。
相信看到这里,心中大概有个结论了吧。
哥们,你真以为你会做这道JVM面试题?的更多相关文章
- 这道面试必问的JVM面试题70%的Java程序员会做错
前言 聊聊JVM,一个熟悉又陌生的名词,从认识Java的第一天起,我们就会听到这个名字,在参加工作的前一两年,面试的时候还会经常被问到JDK,JRE,JVM这三者的区别. JVM可以说和我们是老朋友了 ...
- 这道js面试题号称99%的人会做错
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 【web前端面试题整理01】各位加班累了吧,来做点前端面试题吧
前言 最近小叶子有点疲惫,主要是在外地工作生活上不太适应,吃一样的东西,我居然会拉肚子,而且是一个星期一个星期的.... 脸上长了一个豆豆一个星期还没消,我那个去啊. 昨天上午上班后,本来想继续研究j ...
- 总结一下今天做的unity面试题(一):刚体的点击事件
按照需求,由于要模拟丧尸被击中的效果,不能使用CharactorControll组件,只能使用rigidbody组件. 首先在场景上摆好僵尸和相机的位置,这里就不给相机加脚本了,直接固定住. 然后给丧 ...
- 【web前端面试题整理05】做几道前端面试题休息休息吧
前言 连续学了两天javascript的东西了,我们都累了,于是今天还是上一套面试题吧,大家一起休息休息,也为下个星期可能会有的面试准备下. 题目一览 CSS1. overflow-x 属于 CS ...
- 算法笔记_108:第四届蓝桥杯软件类省赛真题(JAVA软件开发本科A组)试题解答
目录 1 世纪末的星期 2 振兴中华 3 梅森素数 4 颠倒的价牌 5 三部排序 6 逆波兰表达式 7 错误票据 8 带分数 9 剪格子 10 大臣的旅费 前言:以下试题解答代码部分仅供参考,若有不 ...
- 算法笔记_112:第五届蓝桥杯软件类省赛真题(Java本科B组)试题解答
目录 1 武功秘籍 2 切面条 3 猜字母 4 大衍数列 5 圆周率 6 奇怪的分式 7 扑克序列 8 分糖果 9 地宫取宝 10 矩阵翻硬币 前言:以下试题解答代码部分仅供参考,若有不当之处, ...
- 算法笔记_111:第五届蓝桥杯软件类省赛真题(Java本科A组)试题解答
目录 1 猜年龄 2 李白打酒 3 神奇算式 4 写日志 5 锦标赛 6 六角填数 7 绳圈 8 兰顿蚂蚁 9 斐波那契 10 波动数列 前言:以下试题解答代码部分仅供参考,若有不当之处,还请路 ...
- 这道javascript 面试题 你必须会
实现一个函数,运算结果可以满足如下预期结果: add(1)(2) // 3 add(1, 2, 3)(10) // 16 add(1)(2)(3)(4)(5) // 15 话不多说,实现如下: fun ...
随机推荐
- 《DOM Scripting》学习笔记-——第三章 DOM
<Dom Scripting>学习笔记 第三章 DOM 本章内容: 1.节点的概念. 2.四个DOM方法:getElementById, getElementsByTagName, get ...
- AltiumDesigner 查找相似对象
同类器件的集体选中.集体选中的方法是:先选中一个标识符,右击在选项表中选择Find Similar Objects,然后就会出现一个对话框,在这个对话框中,有一些any项,根据自己的需要把一些any改 ...
- FortiGate数据流分析 debug flow
1.工具说明 在防火墙部署中,经常会遇到防火墙接收到了数据包,但并未进行转发.可以通过diagnose debug flow 命令来对数据包的处理过程进行跟踪,可以清晰查看数据包再各个功能模块内的处理 ...
- 20172325 2018-2019-2 《Java程序设计》第七周学习总结
20172325 2018-2019-2 <Java程序设计>第七周学习总结 教材学习内容总结 二叉查找树 二叉查找树:是含附加属性的二叉树,即其左孩子小于父节点,而父节点又小于或等于右孩 ...
- python页面解析_beautifulsoup试玩
最近玩爬虫,先把python解析器 beautifulsoup 练练 这个 tainiu.html 是从百度网盘里拷贝一段html from bs4 importBeautifulSoup wit ...
- C++ static 静态变量&静态成员函数
.h文件中定义 static变量后,如 static QTcpSocket * socket; 那么一定要在.cpp中 构造函数的外面将其初始化为 QTcpSocket * Cfiletransfer ...
- flask通过form表单一次上传多个文件
基本上,用了flask官网的示例代码(中文版,英文版),稍微做了修改. import os from flask import Flask, flash, request, redirect, url ...
- shell脚本学习-执行
跟着RUNOOB网站的教程学习的笔记 Shell与Shell脚本 Shell是用户与Linux系统的桥梁.它既是一种命令语言,也是一种程序设计语言. Shell脚本是一种Shell编写的脚本程序,其实 ...
- docker gitlab安装
mkdir -p /data/docker/volumes/gitlab chmod 777 /data/docker/volumes/gitlab cd /data/docker/volumes/g ...
- python bittorrent 使用与学习
更新于20171128 关于这个p2p的技术,阿里开源了蜻蜓,大家可以看看,感觉应该比这个要好用,而且文档也全. 前言 最近在学习python的p2p协议,发现网上找不到好的文章,又仔细找了找终于找到 ...