一、基础知识
Java从编码到执行
2、从跨平台的语言(java)到跨语言的平台(jvm)
3、JVM是一种规范,任何语言只要能编译成class文件,都能在jvm上运行
字节码指令集(汇编语言)
内存管理:栈、堆、方法区等
4、常见的JVM实现
JDK8以后的Hotspot JVM需要收费,Taobao VM免费
5、JDK JRE JVM
二、Class File Format
- 二进制字节流
- 数据类型: 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 Loading Linking Initializing 类加载-初始化
1、加载过程
(1)Loadding 把class文件load到内存(转成二进制字节)
(2)Linking
verification
校验(是否符合Class文件的标准)
preparation
class文件的静态变量赋默认值
resolution
将类、方法、属性等符号引用解析为直接引用
常量池中的各种符号引用解析为指针,偏移量等内存地址的直接引用
(3)Initializing
调用静态代码块,静态成员变量赋初始值
2、类加载器
任何一个Class类 Load到内存之后,在内存中占了两块儿内容,一块儿是二进制字节码,另一块儿是Class类的对象,指向了对应的二进制字节码
通过对象去访问二进制文件,这个对象是在metespace(元空间)
启动类加载器(Bootstrap ClassLoader)
- 负责加载 JAVA_HOME\lib 目录中的,或通过-Xbootclasspath 参数指定路径中的,且被
虚拟机认可(按文件名识别,如 rt.jar)的类。
扩展类加载器(Extension ClassLoader)
- 负责加载 JAVA_HOME\lib\ext 目录中的,或通过 java.ext.dirs 系统变量指定路径中的类
库。
应用程序类加载器(Application ClassLoader):
- 负责加载用户路径(classpath)上的类库。
JVM 通过双亲委派模型进行类的加载,当然我们也可以通过继承 java.lang.ClassLoader
实现自定义的类加载器。
3、双亲委派
一个孩子向父亲方向,然后父亲向孩子方向的双亲委派过程(双亲:从子到父,从父到子)
作用目的:安全。
主要问题:防止自定义类扰乱。
次要问题:不需要重新加载(防止资源浪费)
简介:
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。采用双亲委派的一个好处是比如加载位于 rt.jar 包中的类 java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个 Object 对象。
4、类加载器的范围
5、自定义类加载器
自定义的类加载器可以用来加载自己加密后的class
/**
* 自定义类加载器
*/
publicclassZywClassLoaderextendsClassLoader{
/**
* 重写findClass方法
* @param name
* @return
* @throws ClassNotFoundException
*/
@Override
protectedClass<?>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)混合模式
(2)lazyloading 懒加载
1.8之前
逻辑上:Method Area方法区:常量池、class各种信息
实际落地在永久代
1.8之后
metespace(元空间)