当前位置: 首页 > news >正文

6.java反射

反射

1.反射机制概述

  • Java反射机制是指在运行时动态获取类的信息或动态调用对象的方法、修改属性等操作。主要核心就是Class类、Constructor类、Field类、Method类等API。 反射机制主要应用于框架开发、动态代理、ORM框架、JDBC驱动等方面。通过反射机制,程序员能够获得在编译期间不被知晓的类、属性、方法等信息。但是反射机制的性能较低,常常被认为是一种牺牲性能换取灵活性的实现方式。

  • Java反射机制核心包:java.lang.reflect.*

  • Java反射机制核心类:

    • java.lang.Class

    • java.lang.reflect.Field

    • java.lang.reflect.Method

    • java.lang.reflect.Constructor

    • java.lang.reflect.Modifier

2.获取Class

Java中获取Class对象有以下三种方式:
  • 调用Object类的getClass()方法:可以通过对象的getClass()方法来获取Class对象,例如:

    Object obj = new Object();
    Class clazz = obj.getClass();
    
  • 使用“类.class”语法:可以使用“类.class”语法来获取Class对象,例如:

    Class clazz = Object.class;
    
  • 使用Class类的forName()方法:可以使用Class类的forName()方法来获取Class对象,例如:

    Class clazz = Class.forName("java.lang.Object");
    

3.反射作用的体现

  • 在属性配置文件中配置类名:classInfo.properties

    className=java.util.Date
    
  • 通过IO流读取属性配置文件,获取类名,再通过反射机制实例化对象。

  • 如果要创建其他类的实例对象,只需要修改classInfo.properties配置文件即可。

  • 这说明反射机制可以让程序变的更加灵活。在进行系统扩展时,可以达到OCP开闭原则。

4.反射Field(属性)

反射Field包括两方面:

  • 一方面:通过反射机制获取Field

    Field field = clazz.getDeclaredField("fieldName"); // 通过属性名获取 
    Field[] fields = clazz.getDeclaredFields(); // 获取所有的属性,包括私有的
    
  • 另一方面:通过Filed访问对象的属性

    Object fieldValue = field.get(myObject); // 读取某个对象的属性值
    field.set(myObject, newValue); // 修改某个对象的属性值
    
public class ReflectionExample {public static void main(String[] args) throws Exception {// 获取类的Class对象Class<?> clazz = Person.class;// 创建对象实例Person person = new Person("张三", 20);// 获取name属性Field nameField = clazz.getDeclaredField("name");// 设置可访问(如果是私有属性)nameField.setAccessible(true);// 读取属性值String name = (String) nameField.get(person);System.out.println("原始姓名:" + name);// 修改属性值nameField.set(person, "李四");System.out.println("修改后姓名:" + person.getName());}static class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}}
}

5.反射Method

反射Method包括两方面:

  • 一方面:通过反射机制获取Method

      Method method = clazz.getDeclaredMethod("methodName", paramTypes);
    
  • 另一方面:通过Method调用方法

      Class clazz = MyClass.class;Method method = clazz.getDeclaredMethod("methodName", paramTypes);Object[] args = {arg1, arg2, arg3};Object result = method.invoke(myObject, args);
    
public class MethodReflectionExample {public static void main(String[] args) throws Exception {// 获取目标类的Class对象Class<?> clazz = Calculator.class;// 创建对象实例Calculator calculator = new Calculator();// 获取add方法(参数为两个int类型)Method addMethod = clazz.getDeclaredMethod("add", int.class, int.class);// 调用方法Object result = addMethod.invoke(calculator, 10, 20);System.out.println("10 + 20 = " + result);// 获取私有方法multiplyMethod multiplyMethod = clazz.getDeclaredMethod("multiply", int.class, int.class);// 设置私有方法可访问multiplyMethod.setAccessible(true);// 调用私有方法Object multiplyResult = multiplyMethod.invoke(calculator, 5, 6);System.out.println("5 × 6 = " + multiplyResult);}static class Calculator {// 公有方法public int add(int a, int b) {return a + b;}// 私有方法private int multiply(int a, int b) {return a * b;}}
}

6.反射Constructor

反射Constructor包括两方面:

  • 一方面:通过反射机制获取Constructor

      Constructor constructor2 = clazz.getDeclaredConstructor(paramTypes); 
    
  • 另一方面:通过Constructor创建对象

    Class clazz = MyClass.class;
    Constructor constructor = clazz.getDeclaredConstructor(paramTypes);
    Object[] args = {arg1, arg2, arg3};
    Object myObject = constructor.newInstance(args);
    
public class ConstructorReflectionExample {public static void main(String[] args) throws Exception {// 获取目标类的Class对象Class<?> clazz = Person.class;// 获取有参构造方法(参数为String和int类型)Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);// 使用构造方法创建对象Object person = constructor.newInstance("张三", 20);System.out.println(person);// 获取私有构造方法Constructor<?> privateConstructor = clazz.getDeclaredConstructor(int.class);// 设置私有构造方法可访问privateConstructor.setAccessible(true);// 使用私有构造方法创建对象Object person2 = privateConstructor.newInstance(30);System.out.println(person2);}static class Person {private String name;private int age;// 公有有参构造方法public Person(String name, int age) {this.name = name;this.age = age;}// 私有构造方法private Person(int age) {this.name = "默认名称";this.age = age;}@Overridepublic String toString() {return "Person{name='" + name + "', age=" + age + "}";}}
}

7.模拟框架的部分实现

  • 配置文件中配置如下信息:classInfo.properties

    className=com.powernode.javase.reflect.UserService
    methodName=login
    parameterTypes=java.lang.String,java.lang.String
    parameterValues=admin,123456
    
  • 通过反射机制创建对象,调用配置的方法

  • 本案例的实现类似于Spring框架中部分实现,主要是通过修改配置文件来达到创建不同的对象,调用不同的方法。

public class ReflectionDemo {public static void main(String[] args) {// 1. 读取配置文件Properties properties = new Properties();try {// 加载配置文件properties.load(new FileInputStream("classInfo.properties"));// 2. 获取配置信息String className = properties.getProperty("className");String methodName = properties.getProperty("methodName");String parameterTypesStr = properties.getProperty("parameterTypes");String parameterValuesStr = properties.getProperty("parameterValues");// 3. 解析参数类型String[] parameterTypeNames = parameterTypesStr.split(",");Class<?>[] parameterTypes = new Class[parameterTypeNames.length];for (int i = 0; i < parameterTypeNames.length; i++) {parameterTypes[i] = Class.forName(parameterTypeNames[i]);}// 4. 解析参数值String[] parameterValues = parameterValuesStr.split(",");// 5. 加载类并获取Class对象Class<?> clazz = Class.forName(className);// 6. 创建对象实例(这里使用无参构造方法)Object obj = clazz.newInstance();// 7. 获取要调用的方法Method method = clazz.getDeclaredMethod(methodName, parameterTypes);// 8. 调用方法(需要将字符串参数转换为对应类型)Object result = method.invoke(obj, (Object[]) parameterValues);// 9. 输出结果System.out.println("方法执行结果:" + result);} catch (IOException e) {System.out.println("配置文件读取失败:" + e.getMessage());} catch (Exception e) {System.out.println("反射操作失败:" + e.getMessage());e.printStackTrace();}}
}public class UserService {/*** 登录方法* @param username 用户名* @param password 密码* @return 登录结果*/public String login(String username, String password) {// 模拟登录验证逻辑if ("admin".equals(username) && "123456".equals(password)) {return "登录成功,欢迎回来," + username + "!";} else {return "登录失败,用户名或密码错误";}}
}

8.类加载及双亲委派机制

类加载的过程
  • 装载(loading)

    • 类加载器负责将类的class文件读入内存,并创建一个java.lang.Class对象
  • 连接(linking)

    • 验证(Verify)

      • 确保加载类的信息符合JVM规范。
    • 准备(Prepare)

      • 正式为静态变量在方法区中开辟存储空间并设置默认值

      • public static int k = 10; 此时:k会赋值0

      • public static final int f = 10; 此时: f会赋值10

    • 解析(Resolve)

      • 将虚拟机常量池内的符号引用替换为直接引用(地址)的过程。
  • 初始化(initialization)

    • 静态变量赋值,静态代码块执行

低版本的JDK中类加载器的名字:

启动类加载器:负责加载rt.jar

扩展类加载器:ext/*.jar

系统类加载器:classpath

获取Class的四种方式
  • 静态方法

    Class clazz = Class.forName(“全限定类名”)
    
  • 实例方法

    Class clazz = 引用.getClass();
    
  • class属性

    Class clazz = 类型名.class;
    
  • 通过类加载器获取

    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    Class clazz = classLoader.loadClass(“全限定类名”);
    

Class.forName和classLoader.loadClass()的区别?

  • Class.forName():类加载时会进行初始化。

  • classLoader.loadClass():类加载时不会进行初始化,直到第一次使用该类。

类加载器
  • 虚拟机内部提供了三种类加载器(Java9+):

    • 启动类加载器(BootstrapClassLoader):加载Java最核心的类,例如String

    • 平台类加载器(PlatformClassLoader):加载Java平台扩展的类库,例如解析XML的

    • 应用类加载器(AppClassLoader):加载classpath中的

    • 同时我们还可以自定义一个类加载器(UserClassLoader)

获取类加载器可以通过 getParent()方法一级一级获取

public class ClassLoaderTest {public static void main(String[] args) {// 获取应用类加载器ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();System.out.println("应用类加载器:" + appClassLoader); // AppClassLoader// 获取平台类加载器(父加载器)ClassLoader platformClassLoader = appClassLoader.getParent();System.out.println("平台类加载器:" + platformClassLoader); // PlatformClassLoader// 获取启动类加载器(父加载器,返回null,因为是C实现)ClassLoader bootstrapClassLoader = platformClassLoader.getParent();System.out.println("启动类加载器:" + bootstrapClassLoader); // null}
}
双亲委派机制
  • 某个类加载器接收到加载类的任务时,通常委托给“父 类加载”完成加载。

  • 最“父 类加载器”无法加载时,一级一级向下委托加载任务。

  • 作用:

    • 保护程序的安全。

    • 防止类加载重复。

举例说明

以加载com.example.MyClass类为例,流程如下:

  1. 应用类加载器(子)收到请求,先委托给父加载器 —— 平台类加载器。
  2. 平台类加载器再委托给父加载器 —— 启动类加载器。
  3. 启动类加载器检查后发现com.example.MyClass不在自己的加载范围内(它只加载核心类),无法加载。
  4. 任务退回给平台类加载器,平台类加载器也无法加载(它加载平台扩展类),再次退回。
  5. 最终由应用类加载器(最初的子加载器)加载com.example.MyClass(因为它在 classpath 下)。

9.反射泛型

  • 反射父类的泛型

  • 反射接口的泛型

  • 反射属性上的泛型

  • 反射方法参数上的泛型

  • 反射方法返回值的泛型

  • 反射构造方法参数上的泛型

http://www.dtcms.com/a/466759.html

相关文章:

  • 怎么做淘宝客个人网站网站程序模板
  • 即梦图片批量去水印软件运营大管家AI图片去水印工具
  • 做网站怎么套模板网站站建设建技设术技术
  • Vue 程序使用host 0.0.0.0 实现监听本机所有可用的网络接口
  • ts-jest与其他TypeScript测试工具的对比
  • 学习16天:pytest学习
  • 奉贤青岛网站建设广州市制网公司
  • 江西中恒建设集团网站网站字体怎么设置
  • 泰安网站制作哪家好网站建设目的分析
  • 怎么看网站开发者页面渗透wordpress论坛
  • 求个网站好人有好报百度贴吧商城类网站建设方案
  • 使用 python-docx 库操作 word 文档(3):读取word文档的内容
  • 鸿蒙:从相册中选取图片,并转成PixelMap作为UI显示
  • 什么是网站什么是网址东莞网站设计服务商
  • STM32 读取引脚状态 -按键输入
  • 关于网站建设分类名字logo设计在线生成免费
  • 网站的二级网页关键词在线一键生成网页
  • 深圳夫博网站建设有限公司深夜的fm免费看
  • MySQL学习笔记09:MySQL高级特性深度学习(上):count函数、数据类型与分库分表核心原理
  • 失智老年人照护实训室建设指南:从意义到实践的全面解析
  • 10分钟上手OpenAI Agents SDK
  • 中文分析原始
  • JP4-8-MyLesson前台前端(二)
  • 做js题目的网站上海网站建设公司推荐排名
  • 网站建设效益分析代运营合同模板
  • 京东商品关键字搜索接口深度开发:从精准检索到商业机会挖掘的技术实现
  • 怎么看网站开发的发展wordpress能开发app
  • 项目学习总结:LVGL图形参数动态变化、开发板的GDB调试、sqlite3移植、MQTT协议、心跳包
  • 统一高效图像生成与编辑!百度新加坡国立提出Query-Kontext,多项任务“反杀”专用模型
  • 网站建设要那些东西适合个人开店的外贸平台