概述

类加载:将类从class文件加载到内存中,并且对字节码进行校验、准备、解析和初始化,最终转换为可以被JVM直接使用的Java类型。

类加载的过程

加载——验证——准备——解析——初始化——使用——卸载

准备

虚拟机在准备阶段为类变量(static修饰)分配内存,并设置类变量的初始值。这些内存是在哪里分配的?堆里?答案是方法区。

而实例变量则是在初始化阶段随对象一起分配在堆内存。而且这里要注意private static int a = 1;在准备阶段,a为0而不为1,在初始化阶段,a才被赋为1

解析

解析阶段是将 常量池中的符号引用替换为直接引用

初始化

遇到下列4种情况,必须对类进行初始化

(1)有new、getstatic、putstatic、invokestatic

(2)反射调用时,如果类没有初始化,就必须首先对类初始化

(3)初始化一个类时,如果父类没有被初始化,就首先对父类进行初始化。

(4)虚拟机启动时需要指定一个主类(main方法所在的类),虚拟机必须首先对其初始化

监控类的加载

-XX:+TraceClassLoading

被动引用不会触发类的初始化

(1)子类引用父类的静态字段,不会引起子类的初始化


class Father{ public static int a = 1; static{
System.out.println("father");
} } class Son extends Father{ public static int b = 2; static {
System.out.println("son");
} } public class ClassLoaderDemo { public static void main(String[] args) {
System.out.println(Son.a);
} }

原因是,该静态变量虽然是子类引用,但底层还是属于父类的。

(2)通过数组定义引用类,不会触发类的初始化


public class ClassLoaderDemo { public static void main(String[] args) {
Father[] fathers = new Father[10];
} }

只加载,并未初始化。

(3)常量在编译的阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量类的初始化


class Father{ public static final int a = 1; static{
System.out.println("father");
} } public class ClassLoaderDemo { public static void main(String[] args) {
System.out.println(Father.a);
} }

对象占用空间计算

dir

类加载器

运行期间动态加载

JVM对class文件并不是全部加载,而是按需加载,需要的时候才会加载进来。

启动时加参数-verbose:class,打印类加载顺序。


class A{
static {
System.out.println("A");
}
}
public class ClassLoaderDemo2 { public static void main(String[] args) {
System.out.println(String.valueOf("test"));
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
A a = new A();
} }

运行结果,会发现只有当执行到new A()是,A类才会被加载进来。

双亲委派机制

先委托父类加载器寻找目标类,在找不到的情况下,在自己的路径中查找目标类。

是否可以创建一个全限定名相同的String类

不可以。当AppClassLoader加载该String时,判断java.lang.String已经加载,便不会再次加载。所以执行的依旧是jdk中的String,但是系统的java.lang.String中没有main()方法,所以会报错。这是一种安全机制。


package java.lang; public class String { public static void main(String[] args) {
System.out.println("test");
} }

异常信息如下

那么String是由哪个加载器加载的?

打印为null,说明是启动类加载器加载的,由于该加载器是C++实现,所以返回null。


public class ClassLoaderDemo2 { @Test
public void testStringClassLoader(){
// 打印为null,说明是启动类加载器加载的,由于该加载器是C++实现,所以返回null
System.out.println(String.class.getClass().getClassLoader());
} }

启动类加载器(Bootstrap CLassLoader)

无法被Java程序直接引用。它属于JVM内部使用的类加载器,既没有上级类加载器,也没有下级类加载器,因此不遵守ClassLoader的上级委托机制,只能算是JVM的一个类加载工具。

扩展类加载器(Extension CLassLoader)

应用程序类加载器(Application CLassLoader)

1、为什么Java可以跨平台

因为有java虚拟机,跨平台是因为字节码即class文件具有平台无关性,java代码会经过java虚拟机转换为字节码

2、class文件的结构

class文件主要是以8位字节码为基本单位的二进制文件,主要的存储方式是以类似于c语言的结构体来存储,其中的两种基本类型为无符号数和表,其中表中又会有其他的表和一些无符号数。就好比结构体中有一些变量,还有一些其他的结构体

class文件的不同位置是固定的,第一个字节码是魔数,紧接着是次版本、主版本、常量池变量数,常量池变量表.......


<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency>

//计算指定对象及其引用树上的所有对象的综合大小,单位字节

long RamUsageEstimator.sizeOf(Object obj)

//计算指定对象本身在堆空间的大小,单位字节

long RamUsageEstimator.shallowSizeOf(Object obj)

//计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB

String RamUsageEstimator.humanSizeOf(Object obj)


public class A { static{
System.out.println("A");
} } public class B extends A{ static{
System.out.println("B");
} }

Java虚拟机——类的结构与加载的更多相关文章

  1. windows/tomcat 修改java虚拟机JVM以utf-8字符集加载class文件的两种方式

      1.情景展示 做了这么长时间的java开发,但是,你知道JVM是以怎样的编码加载.解析class文件的吗? 我们知道,通常情况下,我们会将java文件的字符集修改成utf-8,这样,理所当然地就认 ...

  2. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  3. java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  4. java类的编译、加载和执行

    一.java类的编译流程 这里主要讲的是从java文件到class文件 下图是java类编译的详细步骤: 1.词法分析:将java源代码的字符流转变为标记(Token)的集合,Token是编译过程中的 ...

  5. (转)java类到底是如何加载并初始化的?

    Java虚拟机如何把编译好的.class文件加载到虚拟机里面?加载之后如何初始化类?静态类变量和实例类变量的初始化过程是否相同,分别是如何初始化的呢?这篇文章就 是解决上面3个问题的. 若有不正之处, ...

  6. java中class.forName和classLoader加载类的区分

     java中class.forName和classLoader都可用来对类进行加载.前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块.而classLoade ...

  7. java类在何时被加载

    我们接着上一章的代码继续来了解一下java类是在什么时候加载的.在开始验证之前,我们现在IDEA做如下配置. -XX:+TraceClassLoading 监控类的加载 我们新建了一个TestCont ...

  8. 你知道 Java 类是如何被加载的吗?

    前言 最近给一个非 Java 方向的朋友讲了下双亲委派模型,朋友让我写篇文章深度研究下JVM 的 ClassLoader,我确实也好久没写 JVM 相关的文章了,有点手痒痒,涂了皮炎平也抑制不住的那种 ...

  9. Java 类中各成分加载顺序 和 内存中的存放位置

    参加一个笔试,有一个关于类的静态代码块.构造代码块.构造函数的执行顺序的问题.不太清楚,网上百度了一下.在这里记录一下. 一.什么时候会加载类?使用到类中的内容时加载:有三种情况1.创建对象:new ...

随机推荐

  1. pycharm无法使用ctrl+c/v复制粘贴的问题

    最近在使用pycharm的时候发现不能正常使用ctrl+c/v进行复制粘贴,也无法使用tab键对大段代码进行整体缩进.后来发现是因为安装了vim插件的问题,在setting里找到vim插件,取消勾选即 ...

  2. 基于模型的特征选择详解 (Embedded & Wrapper)

    目录 基于模型的特征选择详解 (Embedded & Wrapper) 1. 线性模型和正则化(Embedded方式) 2. 基于树模型的特征选择(Embedded方式) 3. 顶层特征选择算 ...

  3. Servlet中的jsp内置对象

    Servlet和jsp本质相同,那么为什么还要使用jsp呢,原来的servlet又有什么不好的呢. Servlet和jsp可以做完全相同的事情,就要借助jsp的内置对象们,比如request,resp ...

  4. Connect To Ubuntu 16.04 / 17.10 / 18.04 Desktop Via Remote Desktop Connection (RDP) With Xrdp

    [1] https://websiteforstudents.com/connect-to-ubuntu-16-04-17-10-18-04-desktop-via-remote-desktop-co ...

  5. js实现图片查看器(图片的缩放、旋转、拖拽)

    一.关于图片查看器. 目前网络上能找到的图片查看器很多,谁便一搜就能出来.如:jquery.iviewer.js.Viewer.js这两个js文件,其中功能也足够满足大部分开发需求.但是单纯的就想实现 ...

  6. 转Centos7.0进入单用户模式修改root密码

    Centos7.0进入单用户模式修改root密码   启动Centos7 ,按空格让其停留在如下界面. 按e进行编辑 在UTF-8后面输入init=/bin/sh 根据提示按ctrl+x 得如下图 输 ...

  7. Ubuntu英文变为中文

    Ubuntu英文变为中文 注:(我也是第一次变语言,写的有点乱,我把重点的用红字表示.)     1.点击这个软件更新.  2.只有点击了上面那一步,这里才会软件资源 Software Sources ...

  8. day_3各种数据类型与各种运算符

    首先我们复习一下昨天的内容 1:语言的分类: --有三种 机器语言,汇编语言,高级语言 运行的效率是机器语言最高  开发效率 是高级语言最高 2:计算机由五大部分组成:控制器+运算器+存储器+inpu ...

  9. Struts2新漏洞S2-046在线实验环境全球首发

    Strust2 又出现漏洞啦?搞事情啊? 据说S2-046漏洞和S2-045漏洞非常相似,都是由报错信息带入了buildErrorMessage方法造成的, 只是这次存在两个触发点哦!危害嘛,你说嘞? ...

  10. Android 关于解决MediaButton学习到的media控制流程

    问题背景:话机连接了头戴式的耳机,在通话过程中短按按钮是挂断电话,长按按钮是通话静音.客户需求是把长按改成挂断功能,短按是静音功能. android版本:8.1 在通话中,测试打印信息,可以看到but ...