Java从入门到精通23==》类加载器、反射、反射练习
文章目录
一、类加载器
在Java中,类是通过类加载器加载的。类加载器的任务是将Java字节码转换为在Java虚拟机中可以使用的运行时数据结构。以下是类加载器加载类的步骤:
- 加载:类加载器通过使用类的全限定名来查找该类的二进制字节码文件,并将其读入内存。当类加载器找到类文件后,它会创建一个表示该类的对象(称为Class对象)并将其放入方法区中。
- 链接:链接是将类的二进制数据合并到JRE中的运行时状态中的过程。链接分为三个阶段:
- 验证:验证确保类文件的字节流包含的信息符合Java虚拟机规范,并且没有被篡改。这个过程是为了保证JVM的安全性不受到威胁,是类加载过程中的一个非常重要的部分。
- 准备:在准备阶段,类变量被赋予默认值。这是因为在代码执行之前,需要保证所有类变量都已经被初始化。
- 解析:解析阶段是将符号引用替换为直接引用的过程。由于Java虚拟机运行的是字节码,因此需要将类、方法和字段等符号引用解析为直接引用。
- 初始化:初始化阶段是类加载过程中的最后一步。在这个阶段,执行静态初始化代码块和赋值静态变量的操作。在此之后,类将被视为初始化完成,并且可以被Java虚拟机使用。
二、反射
1、什么是反射
是指在程序运行时,动态地获取类的信息、分析类的信息并操作对象的信息的能力。通过反射,可以在运行时获取类的成员变量、方法、构造函数等信息,还可以创建对象、调用方法、动态修改类的属性和方法等。
2、Class类
1.什么是Class类
Class类是一个Java内置的类,用于描述其他类的结构和行为
2.如何使用
因为没有构造方法,所以使用内部方法创建对象
方式一:
通过Object类中的getClass()方法
代码示例:
Class studentClass1 = student.getClass();
方式二:
通过 类名.class 获取到字节码文件对象
代码示例:
Class studentClass2=Student.class;
方式三:
通过Class类中的方法
代码示例:
try {
Class studentClass3=Class.forName("Class类的创建对象.Student");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
3、通过反射获取构造方法并使用
代码示例:
//获取Class对象
Class calss_studebt = Class.forName("通过反射获取构造方法并使用.Student");
//获取Claa对象的构造器(非私有)
Constructor constructor = calss_studebt.getConstructor(int.class, String.class);
System.out.println(constructor);
//调用构造器
Student student1 = (Student) constructor.newInstance(26, "sdasda");
System.out.println(student1.toString());
//获取Class对象的构造器(私有)
Constructor constructor1 = calss_studebt.getDeclaredConstructor();
System.out.println(constructor1);
//调用私有构造器,创建对象
Student student2 = (Student) constructor1.newInstance();
System.out.println(student2.toString());
结果展示:
4、通过反射获取成员变量进行赋值与获取值操作
代码示例:
//获取Class对象
Class class_student = Class.forName("获取成员变量进行赋值与获取值操作.Student");
//获取构造方法
Constructor constructor = class_student.getConstructor(int.class, String.class);
//创建对象
Student student = (Student)constructor.newInstance(20, "孙悟空");
System.out.println(student);
//获取成员变量(这里的成员变量为私有的)
Field field_name = class_student.getDeclaredField("name");
Field field_age = class_student.getDeclaredField("age");
//”修改“成员变量的权限(暴力破解)
field_age.setAccessible(true);field_name.setAccessible(true);
//取值
System.out.println(field_age.get(student));
System.out.println(field_name.get(student));
//赋值
field_age.set(student,25);
field_name.set(student,"猪八戒");
System.out.println(student);
结果展示:
5、通过反射获取成员方法并使用
代码示例:
.
//获取Class对象
Class class_student =Class.forName("通过反射获取成员方法并使用.Student");
//获取构造方法
Constructor<Student> constructor = class_student.getConstructor(int.class, String.class);
//创建对象
Student student = constructor.newInstance(28,"花蝴蝶");
//获取方法
Method method_getName = class_student.getMethod("getName");
System.out.println(method_getName);
Method method_setName = class_student.getMethod("setName",String.class);
System.out.println(method_setName);
//获取私有方法
Method method_getAge= class_student.getDeclaredMethod("getAge");
System.out.println(method_getAge);
Method method_setAge= class_student.getDeclaredMethod("setAge",int.class);
System.out.println(method_setAge);
//绑定方法给对象并使用
System.out.println(student);
method_setName.invoke(student,"沙和尚");
System.out.println(method_getName.invoke(student));
method_setAge.invoke(student,120);
System.out.println(method_getAge.invoke(student));
System.out.println(student);
结果展示:
这里的Student类是一个标准的JavaBean类,一些方法因为需要被设为私有
package 通过反射获取成员方法并使用;
class Student {
protected int age;
protected String name;
protected Student() {
}
protected int getAge() {
return age;
}
protected void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
三、反射练习
泛型擦除
package 泛型擦除;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//创建一个只能存Integer类型的数组
ArrayList<Integer> list = new ArrayList<>();
list.add(11);
list.add(13);
list.add(15);
//获取Class对象
Class<?> class_Arraylist = Class.forName("java.util.ArrayList");
//通过对象获取add方法,因为泛型值对编译起作用
Method class_add = class_Arraylist.getMethod("add",Object.class);
//这个时候就可以添加String类型的数据
class_add.invoke(list,"lllll");
System.out.println(list);
}
}