Java语言的跨平台特性
java的五大模块
- ClassFile 字节码文件
- 类装载子系统
- 运行时数据区
- 执行引擎(JIT编译器和GC垃圾回收器)
- 本地方法栈
Class File 官方参照 docs.oracle.com/javase/spec…
- Class字节码文件时JVM识别的一种文件,里面地址都是逻辑地址。最后需要运行在操作系统中,由于操作系统只能识别真实的物理地址。此时需要动态链接,即运行时动态的绑定对象、对象地址。
- Class字节码文件是一组以8位字节为基础单位的二进制流,各个数据项严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,整个Class文件存储的内容几乎全部是程序运行所必须数据。
- Class字节码文件只有两种数据类型:无符号数(u)和表(info)
javap -verbose class类名可以看class文件
以下是官方的Class File 文件结构
javac 命令编译生成.class文件 用编辑器以16进制方式打开
以下是部分解析示例 u4 magic ca fe ba be 魔法数表示当前文件是class文件 二进制值 u2 minor_version 00 00 class文件副版本号 0 u2 major_version 00 34 class文件主版本号 52 u2 constant_pool_count 00 25 常量池计数 37 cp_info constant_pool[constant_pool_count - 1] 常量池有36个cp_info结构
以下是官方给出的cp_info结构
解析第一个 cp_info
无符号数 类型 十六进制 十进制 对应表类型
u1 tag 0a 10 CONSTANT_Methodref
u1 info[]
CONSTANT_Methodref的结构
CONSTANT_Methodref_info {
u1 tag; //上面的引用 tag类型的u1 无需解释
u2 class_index;
u2 name_and_type_index;
}
常量池中第一个变量 u2 class_index 00 05 05 类的索引 u2 name_and_type_index; 00 0e 24 名称及类型索引
类装载子系统 Class Loader SubSystem
classfile 通过 class loader 加载到 runtime data area 的过程
链接分为三个阶段
- 验证:验证是否符合虚拟机规范,是否会对jvm造成伤害或侵入性
- 准备:为类加载内存,对类变量进行初始化
- 解析:对虚拟机中常量池的符号引用变为直接引用
最终通过双亲委派机制加载到虚拟机内存当中
ClassLoader 类的 loadClass 方法
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);
}
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
自定义类加载器
public class SelfClassLoader extends ClassLoader{
private String path;
private String clName;
public SelfClassLoader(String path, String clName) {
this.path = path;
this.clName = clName;
}
public SelfClassLoader() {
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] b = loadClassData(name);
return defineClass(name,b,0,b.length);//调用继承类classLoder的defineClass方法定义类
}
private byte[] loadClassData(String name) {
name = path+name.replace(".","\")+".class";
InputStream in = null;
ByteArrayOutputStream out = null;
try {
in = new FileInputStream(new File(name));
out = new ByteArrayOutputStream();
int i = 0;
while ((i=in.read())!=-1){
out.write(i);
}
}catch (Exception e){
}finally {
}
return out.toByteArray();
}
}
ClassLoader的 defineClass 方法
protected final Class<?> defineClass(String name, byte[] b, int off, int len,
ProtectionDomain protectionDomain)
throws ClassFormatError
{
protectionDomain = preDefineClass(name, protectionDomain);
String source = defineClassSourceLocation(protectionDomain);
Class<?> c = defineClass1(name, b, off, len, protectionDomain, source);
postDefineClass(c, protectionDomain);
return c;
}