简述
反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息(如成员变量,构造器,成员方法等),并能操作对象的属性及方法。反射机制在设计模式和框架底层都能用到。
类一旦加载,在堆中会产生一个Class类型的对象,这个对象包含了类的完整结构信息。通过这个对象可以获得这个类的结构。
java反射机制相关类
java作为面向对象的编程语言,万物皆对象,在反射机制中,将类的各个成员都当做一个类的对象
①java.lang.Class:Class对象表示某个类加载后在堆中的对象
②java.lang.reflect.Method:代表类的方法
③java.lang.reflect.Field:代表类的成员变量
④java.lang.reflect.Constructor:代表类的构造器
反射机制优缺点
优点:可以动态的创建和使用对象,使用灵活,反射机制就是框架的底层支撑
缺点:使用反射的运行效率较慢
反射机制优化
关闭访问检查,Method,Field,Constructor均有setAccessible(boolean b)方法,作用是开启或关闭访问安全检查开关,参数为true时关闭访问检查,提高反射的效率;参数为false则表示开启访问检查
Class
①Class类也是一个类,只是类名就叫做Class,因此也继承Object类
②Class类对象不是new Class()的形式创建的,而是由系统创建
③对于某一个类的Class类对象,在内存中只有一份,因此类在内存中只加载一次
④通过Class类对象可以获取所加载类的所有接信息
⑤Class对象存放在堆中。
具有Class对象的类型
类,接口,数组,枚举,注解,基本数据类型,void
代码示例:
package com.flash.class_;
import java.io.Serializable;
/**
* @author flash
* @date 2024/06/18 18:08
* 功能描述:枚举拥有 Class 对象的类型
*/
public class AllTypeClass {
public static void main(String[] args) {
// 类
Class<String> cls1 = String.class;
// 接口
Class<Serializable> cls2 = Serializable.class;
// 一维数组
Class<Integer[]> cls3 = Integer[].class;
// 二维数组
Class<float[][]> cls4 = float[][].class;
// 注解
Class<Deprecated> cls5 = Deprecated.class;
// 枚举
Class<Thread.State> cls6 = Thread.State.class;
// 基本数据类型
Class<Long> cls7 = long.class;
// void
Class<Void> cls8 = void.class;
// Class
Class<Class> cls9 = Class.class;
System.out.println("cls1 = " + cls1);
System.out.println("cls2 = " + cls2);
System.out.println("cls3 = " + cls3);
System.out.println("cls4 = " + cls4);
System.out.println("cls5 = " + cls5);
System.out.println("cls6 = " + cls6);
System.out.println("cls7 = " + cls7);
System.out.println("cls8 = " + cls8);
System.out.println("cls9 = " + cls9);
}
}
运行结果:
类加载
基本说明:反射机制是java实现动态语言的关键, 也就是通过反射实现类动态加载
①静态加载:编译时加载相关的类, 如果没有直接报错, 依赖性强
②动态加载:运行时加载需要的类, 如果运行时没有用到该类, 即使不存在这个类也不会报错, 依赖性较弱
类加载时机:
①当创建对象时(new) 静态加载
②当子类被加载时, 父类也被加载 静态加载
③调用类中的静态成员时 静态加载
④反射机制 动态加载
Class类对象创建方式
import com.flash.classReflex.Car;
/**
* @author flash
* @date 2024/06/18 16:28
* 功能描述:演示得到 Class类 对象的各种方式
*/
public class CreateClassInstance {
public static void main(String[] args) throws ClassNotFoundException {
// 1.class.forName
String classAllPath = "com.flash.classReflex.Car";// 通过读取配置文件获取
Class<?> cls1 = Class.forName(classAllPath);
System.out.println("cls1 = " + cls1);
// 2.类名.class, 应用场景: 用于参数传递
Class<Car> cls2 = Car.class;
System.out.println("cls2 = " + cls2);
// 3.通过已有类调用 getClass() 方法, getClass()获得的就是这个对象关联的 Class 的对象
Car car = new Car();
Class<? extends Car> cls3 = car.getClass();
System.out.println("cls3 = " + cls3);
// 4.通过类加载器获取到类的 Class 对象, 共4种
// 先得到类加载器 car
ClassLoader classLoader = car.getClass().getClassLoader();
// 通过类加载器得到 Class 对象
Class<?> cls4 = classLoader.loadClass(classAllPath);
System.out.println("cls4 = " + cls4);
// cls1, cls2, cls3, cls4 一模一样
System.out.println("cls1.hashCode = " + cls1.hashCode());
System.out.println("cls2.hashCode = " + cls2.hashCode());
System.out.println("cls3.hashCode = " + cls3.hashCode());
System.out.println("cls4.hashCode = " + cls4.hashCode());
// 5.基本数据类型按如下方式跌倒CLass类对象
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
Class<Boolean> booleanClass = boolean.class;
// 输出的还是基本数据类型, 有一个自动装箱、拆箱的过程
System.out.println("integerClass = " + integerClass);// int
System.out.println("characterClass = " + characterClass);// char
System.out.println("booleanClass = " + booleanClass);// boolean
// 6.基本数据类型对应的包装类, 可以通过 .TYPE 对到 Class类对象
Class<Integer> type = Integer.TYPE;
Class<Character> type1 = Character.TYPE;
Class<Boolean> type2 = Boolean.TYPE;
// 还是会自动装箱拆箱
System.out.println("type = " + type);
System.out.println("type1 = " + type1);
System.out.println("type2 = " + type2);
System.out.println("integerClass.hashCode = " + integerClass.hashCode());// 1163157884
System.out.println("type.hashCode = " + type.hashCode());// 1163157884
// 二者相等, 说明基本数据类型及他的包装类的 Class类对象 是同一个
}
}
运行结果:
反射获取类的结构信息
代码示例:
// 测试所用类
class PersonDad {
public String dept;
public PersonDad() {
}
public PersonDad(String dept) {
this.dept = dept;
}
public void dadMethod() {
}
}
interface PersonInterface {
}
@Deprecated // 弃用注解
class Person extends PersonDad implements PersonInterface {
// 属性
public String name = "JSON";
protected int age = 20;
String job = "study";
private double sal = -100;
static int a;
final int b = 10;
public Person() {
}
public Person(String name) {
this.name = name;
}
private Person(String dept, String job) {
super(dept);
this.job = job;
}
protected Person(String name, String job, String dept) {
super(dept);
this.name = name;
this.job = job;
}
public Person(String dept, String name, int age, String job, double sal) {
super(dept);
this.name = name;
this.age = age;
this.job = job;
this.sal = sal;
}
// 方法
public void m1(String name, int age) {
}
protected int m2() {
return 0;
}
String m3() {
return null;
}
private void m4() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", job='" + job + '\'' +
", sal=" + sal +
", b=" + b +
'}';
}
}
获取类名
package com.flash.class_;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author flash
* @date 2024/06/19 14:05
* 功能描述:通过反射获取类的结构信息
*/
public class GetClassMessage {
public static void main(String[] args) throws Exception {
// 得到 Class 对象
Class<?> personClass = Class.forName("com.flash.class_.Person");
// getName:获取全类名
System.out.println("获取全类名");
System.out.println("name = " + personClass.getName());
System.out.println("========================================");
// getSimpleName:获取简单类名
System.out.println("获取简单类名");
System.out.println("SimpleName = " + personClass.getSimpleName());
System.out.println("========================================");
运行结果:
获取属性
// getFields:获取所有本类及其父类 public 修饰的属性
System.out.println("获取所有本类及其父类 public 修饰的属性");
for (Field field : personClass.getFields()) {
System.out.println(field.getName());
}
System.out.println("========================================");
// getDeclaredFields:获取本类所有属性, 只有本类的
System.out.println("获取本类所有属性, 只有本类的");
for (Field declaredField : personClass.getDeclaredFields()) {
/*
属性修饰符的值说明:
默认修饰符: 0
public: 1
private: 2
protected: 4
static: 8
final :16
多修饰符时值相加
*/
System.out.println(declaredField.getType().getSimpleName() + " " + declaredField.getName() + " 属性修饰符的值 = " + declaredField.getModifiers());
}
System.out.println("========================================");
运行结果:
获取方法
// getMethods:获取本类及其父类 public 方法
System.out.println("获取本类及其父类 public 方法");
for (Method method : personClass.getMethods()) {
System.out.println(method.getName());
}
System.out.println("========================================");
// getDeclaredMethods:获取本类所有方法, 只有本类的
System.out.println("获取本类所有方法, 只有本类的");
for (Method declaredMethod : personClass.getDeclaredMethods()) {
System.out.println(declaredMethod.getReturnType().getSimpleName() + " " + declaredMethod.getName() + " 方法修饰符的值 = " + declaredMethod.getModifiers());
System.out.print("参数:");
for (Class<?> parameterType : declaredMethod.getParameterTypes()) {
System.out.print(parameterType.getSimpleName() + " ");
}
System.out.println();
}
System.out.println("========================================");
运行结果:
获取构造器
// getConstructors:获取本类 public 构造器
System.out.println("获取本类 public 构造器");
for (Constructor<?> constructor : personClass.getConstructors()) {
System.out.println(constructor.getName());
}
System.out.println("========================================");
// getDeclaredConstructors:获取本类所有构造器
System.out.println("获取本类所有构造器");
for (Constructor<?> declaredConstructor : personClass.getDeclaredConstructors()) {
System.out.println(declaredConstructor.getName());
System.out.print("参数:");
for (Class<?> parameterType : declaredConstructor.getParameterTypes()) {
System.out.print(parameterType.getSimpleName() + " ");
}
System.out.println();
}
System.out.println("========================================");
运行结果:
获取包信息、父类、实现接口、注解信息
// getPackage:获取包信息
System.out.println("获取包信息");
System.out.println("Package = " + personClass.getPackage());
System.out.println("========================================");
// getSuperclass:获取父类
System.out.println("获取父类");
System.out.println(personClass.getSuperclass());
System.out.println("========================================");
// getInterfaces:获取本类实现的接口
System.out.println("获取本类实现的接口");
for (Class<?> anInterface : personClass.getInterfaces()) {
System.out.println(anInterface.getName());
}
System.out.println("========================================");
// getAnnotations:获取注解信息
System.out.println("获取注解信息");
for (Annotation annotation : personClass.getAnnotations()) {
System.out.println("annotation = " + annotation);
}
}
}
运行结果:
反射创建实例对象
package com.flash.class_;
import java.lang.reflect.Constructor;
/**
* @author flash
* @date 2024/06/19 15:11
* 功能描述:通过反射创建对象
*/
public class CreateInstance {
public static void main(String[] args) throws Exception {
// 1.获取 Person 类的 Class对象
Class<?> userClass = Class.forName("com.flash.class_.Person");
// 2.通过public无参构造器创建实例对象
Object o = userClass.newInstance();
System.out.println("o = " + o);
// 3.通过public构造器创建实例对象
// 3.1 创建对应构造器
Constructor<?> constructor = userClass.getConstructor(String.class);
/*
此时 constructor构造器 对应
public Person(String name) {
this.name = name;
}
*/
// 3.2 通过刚才创建的构造器对象传入实参创建对应对象
Object o1 = constructor.newInstance("张三");
System.out.println("o1 = " + o1);
// 4.调用非public构造器
// 4.1 创建对应构造器
Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
// 4.2 本身不能使用 私有 的构造器, 可以设置允许使用, 暂时先理解为暴力破解
declaredConstructor.setAccessible(true);
// 4.3 创建对象
Object o2 = declaredConstructor.newInstance("山理工", "李四");
System.out.println("o2 = " + o2);
System.out.println(userClass.getField("dept").get(o2));
// 5.试一下protected
Constructor<?> constructor1 = userClass.getDeclaredConstructor(String.class, String.class, String.class);
// 非私有的构造方法方法不需要破解也可以使用
Object o3 = constructor1.newInstance("老六", "happy", "打妖怪");
System.out.println("o3 = " + o3);
System.out.println(userClass.getField("dept").get(o3));
}
}
运行结果:
反射访问属性
package com.flash.class_;
import java.lang.reflect.Field;
/**
* @author flash
* @date 2024/06/19 16:13
* 功能描述:反射访问类中的属性及修改
*/
public class AskProperty {
public static void main(String[] args) throws Exception {
Class<?> stuClass = Class.forName("com.flash.class_.Student");
Object o = stuClass.newInstance();
// o的运行类型已经是 Student 了
System.out.println("o的运行类型 = " + o.getClass());
// 使用反射得到 age 属性对象
Field age = stuClass.getField("age");
age.set(o, 88);
System.out.println(o);
// 使用反射操作 name 属性, 私有且静态
Field name = stuClass.getDeclaredField("name");
// 破解
name.setAccessible(true);
// 赋值
name.set(null, "JSON");// 可以为 null, 因为 name 属性就是静态的
// name.set(o, "JSON");
// 输出
System.out.println(o);
// 获取单一属性
System.out.println(name.get(o));// 获取属性 name 的值
}
}
class Student {
private static String name;
public int age;
public Student() {
}
private static String staticMethod() {
System.out.println("我是私有的静态方法");
return "私有的静态方法";
}
public void hi(String s) {
System.out.println("hi~" + s);
}
@Override
public String toString() {
return "Student{" +
"name=" + name + ", " +
"age=" + age +
'}';
}
}
运行结果:
反射调用方法
package com.flash.class_;
import java.lang.reflect.Method;
/**
* @author flash
* @date 2024/06/19 16:24
* 功能描述:通过反射调用方法
*/
public class UseMethod {
public static void main(String[] args) throws Exception {
Class<?> stuClass = Class.forName("com.flash.class_.Student");
// 创建一个 Student 对象
// Object o = stuClass.newInstance();
Object o = stuClass.getConstructor().newInstance();
// 调用 public 方法
Method hi = stuClass.getMethod("hi", String.class);
// Method hi = stuClass.getDeclaredMethod("hi", String.class);
// 调用 对象o 的 hi 方法
hi.invoke(o, "JSON");
// 调用私有的静态方法
Method staticMethod = stuClass.getDeclaredMethod("staticMethod");
// 爆破
staticMethod.setAccessible(true);
// 调用方法
Object invoke = staticMethod.invoke(null);// 返回类型统一为 Object类型, 运行类型该是什么还是什么
System.out.println("返回值invoke运行类型: " + invoke.getClass());
System.out.println("invoke = " + invoke);
// System.out.println(staticMethod.invoke(o));// 因为是静态方法, 所以有没有指定对象都可以调用
}
}
运行结果: