哥们,你真以为你会做这道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 ...
随机推荐
- 从performance_schema中查看MySQL活动Session的详细执行信息
本文出处:http://www.cnblogs.com/wy123/p/7851294.html 在做数据库的异常诊断的时候,之前在SQL Server上的时候,最主要的参考信息之一就是去看当前的活动 ...
- Spring再接触 注入类型
共有三种注入类型 一种是set注入 一种是构造注入 一种是接口注入 最常用的还是set 现在看一下construct 构造注入 在userservice中加入 package com.bjsxt.se ...
- 分库工具mysql
sharding-sphere 比mycat 更方便 在于mycat属于中间件,更复杂,但也支持更多功能.查询功能更强.
- python的int方法实现数据类型转换
int方法默认以十进制来实现数据类型的转换: 举例: str1=" #给定的内容最好是纯数字,当然也可以是数字再掺杂点别的,最好别掺杂,因为会报错 print(type(str1),str) ...
- 求树的重心 poj 1655
题目链接:https://vjudge.net/problem/POJ-1655 这个就是找树的重心,树的重心就是树里面找一个点,使得以这个点为树根的所有的子树中最大的子树节点数最小.题目应该讲的比较 ...
- Sublime Text3快捷键大全
选择类 Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数 ...
- Mybatis配置问题解决Invalid bound statement (not found)
首先这个异常的原因是系统根据Mapper类的方法名找不到对应的映射文件. 网上也搜索了到了类似的文章,一般可以从以下几个点排查: mapper.xml的namespace要写所映射接口的全称类名,而且 ...
- Linux驱动之异步OR同步,阻塞OR非阻塞概念介绍
链接:https://www.zhihu.com/question/19732473/answer/20851256 1.同步与异步同步和异步关注的是消息通信机制 (synchronous commu ...
- trinitycore 魔兽服务器源码分析(一) 网络
trinitycore是游戏服务器的开源代码 许多玩家使用魔兽的数据来进行测试 ,使用它来假设魔兽私服. 官方网址 https://www.trinitycore.org/ 类似的还有mangos ...
- linux debian 9 / centos 7配置postgresSQL数据库
#读者注意:本文可以选择不看解释,直接执行每段的0中的代码 (〇):一些概念(可以跳过直接使用(一)0的代码) 1. 客户端:psql.postgreSQL的命令行客户端程序,在终端输入psql进入p ...