字节码指令集(汇编语言)
内存管理:栈、堆、方法区等
JDK8以后的Hotspot JVM需要收费,Taobao VM免费
二进制字节流
数据类型: u1u2 u4 u8和_info(表类型)
_info的来源是hotspot源码中的写法
查看16进制格式的ClassFile
sublime / notepad
IDEA插件-BinEd
有很多可以观察ByteCode的方法:
iavap
JBE-可以直接修改
JClassLib -IDEA插件之一
class file 构成
classFile {u4magic;u2minor_version;u2major_version;u2constant_poo1_count;cp_info constant_poo7[constant_poo1_count - 1];u2}
校验(是否符合Class文件的标准)
class文件的静态变量赋默认值
将类、方法、属性等符号引用解析为直接引用
常量池中的各种符号引用解析为指针,偏移量等内存地址的直接引用
调用静态代码块,静态成员变量赋初始值
任何一个Class类 Load到内存之后,在内存中占了两块儿内容,一块儿是二进制字节码,另一块儿是Class类的对象,指向了对应的二进制字节码
通过对象去访问二进制文件,这个对象是在metespace(元空间)
负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath 参数指定路径中的,且被
虚拟机认可(按文件名识别,如 rt.jar)的类。
负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类
库。
负责加载用户路径(classpath)上的类库。
JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader
实现自定义的类加载器。
一个孩子向父亲方向,然后父亲向孩子方向的双亲委派过程(双亲:从子到父,从父到子)
作用目的:安全。
主要问题:防止自定义类扰乱。
次要问题:不需要重新加载(防止资源浪费)
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。
自定义的类加载器可以用来加载自己加密后的class
/**
* 自定义类加载器
*/
publicclassZywClassLoaderextendsClassLoader{
/*** 重写findClass方法* @param name* @return* @throws ClassNotFoundException*/@OverrideprotectedClass>findClass(Stringname) throwsClassNotFoundException {//类的绝对路径目录Filef=newFile("D:/develop/minnyouzi/src/main/java/com/example/zyw/entity",name.replaceAll(".","/").concat(".class"));try {FileInputStreamfis=newFileInputStream(f);//将文件转换为二进制字节数组ByteArrayOutputStreambaos=newByteArrayOutputStream();intb=0;//从文件中读出来写进字节数组while ((b=fis.read())!=0){baos.write(b);}
byte [] bytes=baos.toByteArray();baos.close();fis.close();
/*** 将二进制字节数组转换为类对象* name : 转换的类的名字* bytes:字节数组* off:字节数组起始的位置* bytes.length:结束的位置*/returndefineClass(name,bytes,0,bytes.length);}catch (Exceptione){e.printStackTrace();}
returnsuper.findClass(name);//throws ClassNotFoundException
}
publicstaticvoidmain(String[] args) throwsException{ClassLoaderl=newZywClassLoader();Classclazz=l.loadClass("com.example.zyw.entity.User");//通过反射访问Useruser= (User)clazz.newInstance();user.m();System.out.println(l.getClass().getClassLoader());System.out.println(l.getParent());}
}
1.8之前
逻辑上:Method Area方法区:常量池、class各种信息
实际落地在永久代
1.8之后
metespace(元空间)
上一篇:python 正则使用详解
下一篇:构建64位操作系统-中断与异常