1.类加载过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载等七个阶段。
类加载器
加载就是将类的class文件读入内存后,创建一个Class对象,这个过程由类加载器完成,类加载器分为三类:
- 启动类加载器
该加载器负责加载存放在JDK\jre\lib类库,启动加载器是无法被Java程序直接引用,由JVM 调用; - 扩展类加载器
该类加载器负责加载JDK\jre\lib\ext目录中,或者由Java.ext.dirs系统指定的路径中的所有类库(如Javax.*开头的类),开发者可以直接使用扩展类加载器; - 应用类加载器(程序员)
加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器(如果程序中没有自定义类加载器,一般情况下这个就是程序中默认的类加载器
初始化
JVM负责对类进行初始化,也就是对静态属性进行初始化。在Java中,对静态属性初始化的方式有两种:
- 声明静态属性时指定初始值;
- 使用静态初始化代码块为静态属性指定初始值。
类加载过程主要是将Class文件加载到虚拟机内存中,真正执行字节码的操作是在类加载完成后才开始的。
反射
Java反射机制的核心是在程序运行时动态的加载类并获取类的详细信息,从而操作类或对象的属性和方法(本质是JVM得到Class对象后,再通过Class对象经行反编译,从而获取对象的各种信息)
程序运行时,动态的创建对象的方式称为反射
Java属于先编译在运行的语言,对象类型在编译期确定;
当程序在运行时可能需要动态加载某些类,通过反射可以在运行时动态的创建对象并调用其属性,不需要提前在编译期确定对象类型
反射的原理——类加载
传统静态加载类
Person person = new Person();
//编译时已确定对象的属性,程序运行时通过类加载器加载Person类,并创建该类的Class对象
反射动态加载类
Class object = Class.forName("Person");//引号里的是类全名
//编译时未确定对象类型,程序运行时通过类加载器无法加载Person类,只有程序执行到以上代码时,类加载器才知道对象类型,这时才开始加载Person类,创建该类的Class对象,并返回给object变量
Class对象
每一个类通过类加载器完成加载后,都会创建唯一的Class对象,用于保存类的元信息(属性、方法以及构造器)
Class对象属于Class类型,是类加载器创建的特殊对象,不是类的实例化对象
Class object = Class.forName("Person");
Person person =(Person)object.newInstance();
反射通过获得Class对象就可以得到类的元信息,调用newInstance()方法就是通过元信息来创建Person对象实例
三种获取Class对象的方式
- ① 对象名.getclass----------------运行阶段
通过类对象实例的getClass()方法——Person preson = new Person(); Class object = person.getClass();
- ② 类名.class---------------------加载阶段
通过任何数据类型(包括基本数据类型)的静态class属性Class object = Person.class;
- ③ Class.forName ("类全名")---------------------源代码阶段
通过Class类的静态方法:forName(String className)Class object = Class.forName("Person");
注:第一种没必要,第二种需要导入类包依赖太强,第三种简单灵活
具体实现
package reflection;
/**
* @author yeye
* @desc
* @date 2024/8/29 20:11
*/
public class Reflection01 {
public static void main(String[] args) throws ClassNotFoundException {
/**
* 获取Class对象的三种方式
* 1. 通过Class.forName("全类名")方法
* 2. 通过类名.class属性
* 3. 通过对象.getClass()方法
*/
//第一种方式
//全类名“包名.类名”
//最常用
Class clazz = Class.forName("reflection.Reflection01");
System.out.println("第一种方式:" + clazz.getName());
//第二种方式
//一般更多的是当作参数传递给方法,所以用类名.class属性
Class clazz2 = Reflection01.class;
System.out.println("第二种方式:"+clazz2.getName());
//第三种方式
//一般用在对象实例化之后,获取对象的Class对象
Reflection01 obj = new Reflection01();
Class clazz3 = obj.getClass();
System.out.println("第三种方式:"+clazz3.getName());
}
}
两种方式创建对象实例
- 使用Class对象的newInstance()方法
Class object = Class.forName("Person"); Person person = (Person)class.newInstance;
- 使用Class对象获取Constructor对象,再调用newInstance()方法;
Class object = Class.forName("person"); Counstructor constructer = object.getConstructor(Person.class); Person person =(Person)constructor.newInstance("张三",18);
第一张构造器只能调用无参构造器,第二种可以调用有参构造器
反射的基本使用
-
使用Class对象获取Field对象
具体如下代码:Class object = Class.forName("Person"); Field fields[] = object.getDeclearedFields();
package reflection; import java.lang.reflect.Field; /** * @author yeye * @desc 通过反射获取成员变量 * @date 2024/9/1 23:01 */ public class Reflection03 { public static void main(String[] args) throws Exception { //1.获取class字节码文件对象 Class clazz = Class.forName("reflection.Student"); //2.获取成员变量 //获取所有的公共的成员变量 Field[] f1 = clazz.getFields(); for(Field f:f1){ System.out.println(f); } System.out.println("-------------"); //获取所有的成员变量,包括私有的和受保护的 Field[] f2 = clazz.getDeclaredFields(); for(Field f:f2) { System.out.println(f); } System.out.println("-----------------------"); //获取单个成员变量 //获取gender(共有的)成员变量 Field fie1 = clazz.getField("gender"); System.out.println(fie1); //获取name(私有的)成员变量 Field fie2 = clazz.getDeclaredField("name"); System.out.println(fie2); //获取成员变量的名字 String n = fie1.getName(); System.out.println(n); //获取成员变量的类型 Class type = fie2.getType(); System.out.println(type); } }
-
使用Class对象获取Method方法
具体如下代码
package reflection;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
/**
* @author yeye
* @desc 利用反射获取成员方法
* @date 2024/9/2 16:31
*/
public class Reflection04 {
public static void main(String[] args) throws Exception {
//获取class字节码文件对象
Class clazz = Class.forName("reflection.Student");
//获取所有的公共方法(包含父类中所有的公共方法)
Method []method1 = clazz.getMethods();
for(Method method:method1){
System.out.println(method);
}
//获取所有的方法
Method[] method2 = clazz.getDeclaredMethods();
for(Method method:method2){
System.out.println(method);
}
//获取指定的单一方法
Method method3 = clazz.getDeclaredMethod("study",String.class);
System.out.println(method3);
//获取方法的名字
String name = method3.getName();
System.out.println(name);
//获取方法的修饰符
int modifiers = method3.getModifiers();
System.out.println(modifiers);
//获取方法的形参
Parameter[] parameters = method3.getParameters();
for(Parameter parameter:parameters){
System.out.println(parameter);
}
//获取方法的异常
Class[] exceptionTypes = method3.getExceptionTypes();
for(Class exceptionType:exceptionTypes){
System.out.println(exceptionType);
}
//获取方法并运行
Student m = new Student();
method3.setAccessible(true);
//参数一:m,表示方法的调用者
//参数二:"汉堡包",表示在调用方法的时候传递的实际参数
String result = (String) method3.invoke(m, "数学");
System.out.println(result);
}
Field 对象数组保存类的所有属性,Method对象数组保存类的所有方法
3. 获取构造方法
具体如下代码:
package reflection;
import java.lang.reflect.Constructor;
import java.sql.Connection;
/**
* @author yeye
* @desc 通过反射获取类的构造方法
* @date 2024/9/1 21:32
*/
public class Reflection02 {
public static void main(String[] args) throws Exception {
//1、获取class字节码文件对象
Class clazz = Class.forName("reflection.Student");
//2、获取构造方法
//第一种方法,获取所有的公共的构造方法
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con : cons1) {
System.out.println(con);
}
System.out.println("-------");
//第二种方法,获取所有的构造方法,包括私有的
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con : cons2) {
System.out.println(con);
}
System.out.println("-------");
//3、获取单个的空参构造方法
Constructor con1 = clazz.getDeclaredConstructor();
System.out.println(con1);
//4、获取单个的带参数的构造方法(String类型)
Constructor con2 = clazz.getDeclaredConstructor(String.class);
System.out.println(con2);
//5.获取多个参数的构造方法
Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(con3);
//6.创建对象
//第一种方法,调用空参构造方法
Student stu1 = (Student) con1.newInstance();
System.out.println(stu1);
//第二种方法,调用带参构造方法
//暴力反射,表示临时取消权限校验
con3.setAccessible(true);
Student stu2 = (Student) con3.newInstance("椰椰", 20);
System.out.println(stu2);
}
}
标签:反射,Java,System,获取,println,加载,Class,out
From: https://www.cnblogs.com/wmshun/p/18393741