哥们,你真以为你会做这道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 ...
随机推荐
- Echarts 饼状图自定义颜色
今天给饼状图着色问题,找了好久 终于找到了 话不多说直接上代码 $.ajax({ url: "/HuanBaoYunTai/ajax/HuanBaoYunTaiService.ashx&qu ...
- 使用Global.asax的Application_BeginRequest事件过滤客户端XSS恶意脚本提交
XSS攻击全称跨站脚本攻击(Cross Site Scripting),是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码(如HTML代码和客户端脚本)植入到提供给其它用户使用的页面中. ...
- 深入浅出PF 学习笔记---通过资源文件设置按钮的Style及通过x:null设置不受Style影响
<Window x:Class="WpfStudy2018.StyleButton" xmlns="http://schemas.microsoft.com/win ...
- http 连接 analysis service (ssas)
当数据仓库搭建好后,我们就可以通过sqlserver的管理工具查看服务器上的数据集了.但是这样挺不方便的,如果要远程访问,那么就可以通过http来连接数据仓库.要配置数据仓库http连接非常的简单.如 ...
- [leetcode]244. Shortest Word Distance II最短单词距离(允许连环call)
Design a class which receives a list of words in the constructor, and implements a method that takes ...
- 在IDEA中使用MyBatis Generator自动生成代码
转载自 https://blog.csdn.net/hua_faded/article/details/78900780 一.配置Maven pom.xml 文件 在pom.xml增加以下插件: ...
- PHP开发——函数
函数的定义 l 函数是一段命名的代码段. 函数可以减轻工作量,减少重复的代码,方便后期维护. 函数的参数 l 实参:调用函数时,传递的参数就是实参,含有真正数据的. l 形参:定义函数时的参数. ...
- 浅谈卷积和C++实现
1 信号处理中的卷积 无论是信号处理.图像处理还是其他一些领域,我们经常会在一些相互关联的数据处理中使用卷积.卷积可以说是算法中一个非常重要的概念.这个概念最早起源于信号处理之中. 假设对于一个线性系 ...
- JS中的offset scroll event client
一.offset 一般用来检测盒子的偏移.位移,都是只读属性,不能赋值 offsetWidth和offsetHeight表示的是:调用者盒子的宽和高,包括盒子自身的padding和border off ...
- You are using pip version 9.0.1, however version 9.0.3 is available.
1,pip不能用了,提示:You are using pip version 8.1.1, however version 9.0.1 is available.网上搜索了一箩筐的安装程序,各种安装, ...