源代码如下,求结果

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构造函数执行

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

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

看起来很懵的java内存加载面试题的更多相关文章

  1. 很考验人的java内存加载面试题

    源代码如下,求结果 public class MemoryAnalyse { public static int k = 0; public static MemoryAnalyse t1 = new ...

  2. java内存加载机制

    什么是java类加载? 类加载是指将.class类中的二进制数据存放到内存中,会在内存中的推中建立一个java.lang.String的引用对象来存放方法区的数据结构,而类中的数据会放到方法区中 类加 ...

  3. 【设计模式】C++单例模式的几种写法——Java自动加载内部类对象,C++怎么破?

    单例模式是最简单的设计模式,就让我像玩简单的游戏一样写下去吧. v1: 简单模式 和这个版本有过一面之缘,但不敢苟同. class Singleton { private: Singleton() { ...

  4. 原来热加载如此简单,手动写一个 Java 热加载吧

    1. 什么是热加载 热加载是指可以在不重启服务的情况下让更改的代码生效,热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于热加载的不安全性,一般不会用于正式的生产环 ...

  5. Java动态加载类

    详见:https://blog.csdn.net/zai_xia/article/details/80026325 扩展:java反射机制与动态加载类 https://www.cnblogs.com/ ...

  6. java class加载机制及对象生成机制

    java class加载机制及对象生成机制 当使用到某个类,但该类还未初始化,未加载到内存中时会经历类加载.链接.初始化三个步骤完成类的初始化.需要注意的是类的初始化和链接的顺序有可能是互换的. Cl ...

  7. 内存加载DLL

    1.前言 目前很多敏感和重要的DLL(Dynamic-link library) 都没有提供静态版本供编译器进行静态连接(.lib文件),即使提供了静态版本也因为兼容性问题导致无法使用,而只提供DLL ...

  8. Java虚拟机加载类

    Java虚拟机是如何加载Java类的 Java虚拟机加载Java类总共需要经过3步:加载-----链接-----初始化.Java语言的类型可以分为两大类:基本类型和引用类型.基本类型是有Java虚拟机 ...

  9. Java ClassLoader加载机制理解

    今天看到了一篇介绍Java ClassLoader加载机器的文章, 才发觉一直来自己的肤浅, 好好地给补了一课, 不得不存档! 原文地址: http://www.blogjava.net/lhulcn ...

随机推荐

  1. mysql事务(一)——redo log与undo log

    数据事务 即支持ACID四大特性. A:atomicity          原子性——事务中所有操作要么全部执行成功,要么全部执行失败,回滚到初始状态 C:consistency     一致性—— ...

  2. quartz开源作业调度框架的配置

    quartz开源作业调度框架的job服务实现,Quartz是一个完全由java编写的开源作业调度框架,使用时候需要创建一个实现org.quartz.Job接口的java类,Job接口包含唯一的方法: ...

  3. 数据在千万级别上进行全文检索有哪些技术?强大的大数据全文索引解决方案-ClouderaSearch

    数据在千万级别上进行全文检索有哪些技术?强大的大数据全文索引解决方案-ClouderaSearch1.lucene (solr, elasticsearch 都是基于它) 2.sphinx3.elas ...

  4. (四)github之Git的初始设置

    设置姓名与邮箱地址 这里的姓名和邮箱地址会用在git的提交日志之中,在github上公开git仓库时会随着提交日志一起公开. 有两种方式, 第一种,在git bash下设置 第二种, 通过直接编辑.g ...

  5. Python Web学习笔记之CPU时间片

    时间片即CPU分配给各个程序的时间,每个线程被分配一个时间段,称作它的时间片,即该进程允许运行的时间,使各个程序从表面上看是同时进行的.如果在时 间片结束时进程还在运行,则CPU将被剥夺并分配给另一个 ...

  6. 20145307陈俊达《网络对抗》Exp7 网络欺诈技术防范

    20145307陈俊达<网络对抗>Exp7 网络欺诈技术防范 基础问题回答 什么是dns欺骗攻击! 利用dns spoof运行DNS欺骗,如果是请求解析某个域名,dnsspoof会让该域名 ...

  7. 瘋子C语言笔记 (string)

    1.strstr() 函数 搜索一个字符串在另一个字符串中的第一次出现.找到所搜索的字符串,则该函数返回第一次匹配的字符串的地址:如果未找到所搜索的字符串,则返回NULL. 2.strcat() 函数 ...

  8. DDR2是什么意思

    DDR2DDR2(Double Data Rate 2) SDRAM是由JEDEC(电子设备工程联合委员会)进行开发的新生代内存技术标准,它与上一代DDR内存技术标准最大的不同就是,虽然同是采用了在时 ...

  9. git的软件安装

    1.Git for Winodws 1.*的版本   https://github.com/msysgit/msysgit/releases 2.*的版本   https://github.com/g ...

  10. VS不显示最近打开的项目

    VS2012不显示最近打开的项目 解决方法, 在"运行"中输入 " gpedit.msc"打开后在"用户配置"-"管理模板&quo ...