问题
1、为什么要有类加载机制(类加载机制的意义是什么)
2、类加载机制的过程,这些步骤可以颠倒顺序么?,每个步骤的作用是什么?
3、什么情况下必须对类进行初始化
类加载的过程
加载——验证——准备——解析——初始化——使用——卸载
准备
虚拟机在准备阶段为类变量(static修饰)分配内存,并设置类变量的初始值。这些内存是在哪里分配的?堆里?答案是方法区。
而实例变量则是在初始化阶段随对象一起分配在堆内存。而且这里要注意private static int a = 1;在准备阶段,a为0而不为1,在初始化阶段,a才被赋为1
解析
解析阶段是将 常量池中的符号引用替换为直接引用
初始化
遇到下列4种情况,必须对类进行初始化
(1)有new、getstatic、putstatic、invokestatic
(2)反射调用时,如果类没有初始化,就必须首先对类初始化
(3)初始化一个类时,如果父类没有被初始化,就首先对父类进行初始化。
(4)虚拟机启动时需要指定一个主类(main方法所在的类),虚拟机必须首先对其初始化
类加载器
启动类加载器(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");
}
}