java 类加载
反射
-
类加载
加载阶段:JVM在该阶段的主要目的时将字节码从不同的数据源【可能时 class文件, jar包,甚至是网络】转化为二进制字节流加载到内存,并生成一个代表该类的 Class对象;
-
连接阶段:
-
验证阶段:
-
为了确保Class文件的字节流中包含的信息符合jvm的要求,而且不会危害jvm安全;
-
在 loadClass 方法中会生成一个安全管理类SecurityManager,这个类会进行验证
- 文件格式验证,.class文件是否以魔数开头,即:oxcafebabe开头;
- 元数据验证,字节码验证,符号引用验证;
- 考虑使用 -Xverify:none 参数来关闭大部分类的验证措施,以提高效率;
-
准备阶段:
-
jvm 会对静态变量分配内存并初始化【对应数据内省的默认初始化, eg 0, 0L,0.0f,null, false】
-
这些变量都在内存的方法区【与java版本相关】中进行分配;
public int n1 = 10; public static int n2 = 20; public static final int n3 = 30; //1.n1是实例属性,在准备阶段不分配内存; //2.n2是静态属性,在准备阶段分配内存,且默认初始化: 0; //3.n3是static final 常量,一旦赋值就不会改变,n3在准备阶段分配内存,而且默认初始化为 30; //[也可以在静态代码块中初始化,但系统不会在此阶段默认赋值] //当在静态代码块显式初始化的时候,必须加载类; //final 修饰的变量必须显式初始化,且只能赋值一次。
-
-
解析阶段:
-
jvm 将常量池内的符号引用,替换为直接引用的过程;
当还没由加载到内存的时候,是通过变量,符号表示相互之间的引用,
当加载到内存后,jvm分配内存后,使用内存地址,替换以前的符号表示【符号都是在常量池内】;
-
-
-
-
初始化:
-
到了初始化,才开始真正执行类中定义的java代码,在此阶段是执行
()方法的过程; -
()方法是由编译器按照语句在源文件中出现的顺序,依次自动收集类中静态变量的赋值动作和静态代码块中的语句,并进行合并; -
jvm 会保证一个类的
()方法【同步方法】在多线程中会被一个线程执行,其他线程需要阻塞等待,直到执行完毕【所以才会只产生一个Class对象】; static{ num = 100; } public static int num = 300; //在加载的准备阶段,分配了num的内存,并初始化为0; //在初始化阶段,会将: num = 100; num = 300; //合并 => num = 300;
-
通过反射获取类的结构信息:
-
Class类:
getName(); getSimpleName(); getFields(); //获取所有public修饰的属性,包含本类和父类; getDeclaredFielss(); //获取本垒中所有属性; getMethods(); getDeclaredMethods(); getConstructors(); // 获取所有public修饰的构造器,仅本类 getDeClaredConstructors(); getPackage(); //以Package的形式返回 包信息; getSuperClass(); getInterfaces(); getAnnotations();
-
Field类:
getModifiers();//以int形式返回修饰符; // 默认修饰符:0,public:1,private:2,protected:4,static: 8;final: 16,publi + static : 9; getType(); //属性类型的Class对象; getName();//返回属性名;
-
Method类
getModifiers();//以int形式返回修饰符; getReturnType();//返回属性类型的Class对象; getName();//返回方法名; getParameterTypes();//以Class[]返回参数类型数组;
-
Constructor类
getModifiers();//以int形式返回修饰符; getName(); // 全类名:包路径+类名 getParameterTypes();//以Class[]返回参数类型数组;
-
通过反射创建对象:
- 调用类中的public的无参构造器;
- 调用类中的指定构造器;
- Class类的相关方法:
- newInstance():调用类中的无参构造,获取对应类;
- getConstructor(Class clazz):根据参数列表,获取对应构造器对象;
- getDecalaredConstructor(Class clazz):根据参数列表,获取对应构造器对象;
- Constructor类相关方法:
- setAccessible():爆破【将private权限设置为外部类可访问状态:构造器,属性,方法】
- newInstance(Object ...obj):调用构造器;
- Field类的相关方法:
- setAccessible():
- f.set(对象, 值);
- 为什么上传对象,因为只要类加载,对于每一个类就会存在一个Class类,数据结构【属性,构造器,方法】都在Class内,但是却可以有无数个实例对象,普通属性是和实例绑定的,所以,需要传入实例,
- 当为静态变量的时候,实例对象可以传入null【加个方法重载多好】;
- Method类的相关方法:
- setAccessible():
- invoke(对象,实参列表);
- 如果有返回值,编译类型是:Object;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!