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

Java反射机制详解:动态访问和操作对象

目录

  1. 先看个例子
  2. 基本概念
  3. Class 2.1 获取Class 2.2 通过Class获取类修饰符和类型
  4. Member 3.1 Field 3.1.1 获取Field 3.1.2 获取变量类型、修饰符、注解 3.1.3 获取、设置变量值 3.2 Method 3.2.1 获取Method 3.2.2 获取方法返回类型 3.2.3 获取方法参数类型 3.2.4 获取方法声明抛出的异常类型 3.2.5 获取方法参数名称 3.2.6 通过反射调用方法 3.3 Constructor 3.3.1 获取构造方法 3.3.2 创建对象
  5. 数组和枚举 4.1 数组 4.2 枚举
  6. 反射的缺点 参考

1. 先看个例子

public class People {private People(int age) {}public void show() {System.out.println("test reflect");}
}//test code
Class<?> clazz = Class.forName("com.xfhy.ref.People");
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(int.class);
declaredConstructor.setAccessible(true);
People person = (People) declaredConstructor.newInstance(12);
person.show();
通过这个简单的例子,我们可以看到Java反射的强大之处:即使People的构造方法是私有的,我们仍然可以通过反射机制来创建其实例。

2. 基本概念

Java的反射机制能够:

  • 对于任意一个类,都能够知道这个类的所有属性和方法。
  • 对于任意一个对象,都能够调用它的任意一个方法和属性。

这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。反射机制主要涉及两个类:ClassMember

3. Class

Class是反射能够实现的基础,Class是JDK提供的一个类,完整路径是java.lang.Class。本质上这个类和MathString或者自己定义的各种类没有区别。

3.1 获取Class

获取Class对象的几种方法:

  • Object.getClass():对象实例调用getClass方法。
  • The.class:类调用.class,例如String.class
  • Class.forName(""):传入类的全路径。
  • The.TYPE:例如Double.TYPE
  • Class.getSuperclass():某个实例调用getClass().getSuperclass()

3.2 通过Class获取类修饰符和类型

HashMap为例,我们可以通过反射获取类的修饰符、泛型信息、实现的接口、父类和注解等信息。

Class<?> clazz = HashMap.class;
System.out.println("Class : " + clazz.getCanonicalName());
System.out.println(Modifier.toString(clazz.getModifiers()));
TypeVariable<? extends Class<?>>[] typeParameters = clazz.getTypeParameters();
StringBuilder stringBuilder = new StringBuilder("Parameters : ");
for (TypeVariable<? extends Class<?>> typeParameter : typeParameters) {stringBuilder.append(typeParameter.getName()).append(" ");
}
System.out.println(stringBuilder.toString());Type[] genericInterfaces = clazz.getGenericInterfaces();
StringBuilder interfaces = new StringBuilder("Implemented Interfaces : ");
for (Type intf : genericInterfaces) {interfaces.append(intf.toString()).append(" ");
}
System.out.println(interfaces.toString());Class<?> superclass = clazz.getSuperclass();
if (superclass != null) {System.out.println(superclass.getCanonicalName());
}Annotation[] annotations = clazz.getAnnotations();
StringBuilder annotation = new StringBuilder("Annotations : ");
for (Annotation a : annotations) {annotation.append(a.toString()).append(" ");
}
System.out.println(annotation.toString());

4. Member

Member有三个实现类:

  • java.lang.reflect.Field:类变量
  • java.lang.reflect.Method:类方法
  • java.lang.reflect.Constructor:类构造方法

4.1 Field

通过Field可以访问给定类对象的类变量,包括获取变量的类型、修饰符、注解、变量名、变量值等,即使是private的也是OK的。

4.1.1 获取Field

Class提供了四种方法获得给定类的Field

  • getDeclaredField(String name):获取指定的变量,包括private的。
  • getField(String name):获取指定的变量,只能是public的。
  • getDeclaredFields():获取所有变量,包括private的。
  • getFields():获取所有变量,只能是public的。
4.1.2 获取变量类型、修饰符、注解
Class clazz = People.class;
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {StringBuilder stringBuilder = new StringBuilder();stringBuilder.append("变量名: ").append(field.getName()).append("\n");stringBuilder.append("变量类型: ").append(field.getType()).append("\n");stringBuilder.append("变量修饰符: ").append(Modifier.toString(field.getModifiers())).append("\n");Annotation[] annotations = field.getAnnotations();if (annotations.length != 0) {stringBuilder.append(" 变量注解 : ");for (Annotation a : annotations) {stringBuilder.append(a.toString()).append(" ");}}System.out.println(stringBuilder.toString());
}
4.1.3 获取、设置变量值
People people = new People("张三", 17);
Class<? extends People> peopleClass = people.getClass();
try {Field nameField = peopleClass.getDeclaredField("name");nameField.setAccessible(true);Field ageField = peopleClass.getField("age");String name = (String) nameField.get(people);int age = ageField.getInt(people);System.out.println("name = " + name + ", age = " + age);nameField.set(people, "李四");ageField.set(people, 18);System.out.println(people.toString());
} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();
}

4.2 Method

4.2.1 获取Method

Class提供了四种方法获取Method

  • getDeclaredMethod(String name, Class<?>... parameterTypes)
  • getMethod(String name, Class<?>... parameterTypes)
  • getDeclaredMethods()
  • getMethods()
4.2.2 获取方法返回类型
  • getReturnType():获取目标方法返回类型对应的Class对象。
  • getGenericReturnType():获取目标方法返回类型对应的Type对象。
4.2.3 获取方法参数类型
  • getParameterTypes():获取目标方法各参数类型对应的Class对象。
  • getGenericParameterTypes():获取目标方法各参数类型对应的Type对象。
4.2.4 获取方法声明抛出的异常类型
  • getExceptionTypes():获取目标方法抛出的异常类型对应的Class对象。
  • getGenericExceptionTypes():获取目标方法抛出的异常类型对应的Type对象。
4.2.5 获取方法参数名称

.class文件中默认不存储方法参数名称,如果想要获取方法参数名称,需要在编译的时候加上-parameters参数。

4.2.6 通过反射调用方法

通过Methodinvoke()方法来反射调用目标方法,第一个参数为需要调用的目标类对象。如果方法是static的,则该参数为null,后面的参数是目标方法的参数值,顺序与目标方法声明中的参数顺序一致。

4.3 Constructor

4.3.1 获取构造方法

Method类似。

4.3.2 创建对象

一般使用java.lang.reflect.Constructor.newInstance()来构建对象,另一种Class.newInstance()已经废弃。

5. 数组和枚举

5.1 数组

数组类型:数组本质上是一个对象,所以它也有自己的类型。例如对于int[] intArray,数组类型为class [I。数组类中的[个数代表数组的维度,例如[代表一维数组,[[代表二维数组,[后面的字母代表数组元素类型,I代表int,一般为类型的首字母大写(long类型例外,为J)。

创建和初始化数组:

Object array = Array.newInstance(int.class, 2);
Array.set(array, 0, 1);
Array.set(array, 1, 2);
System.out.println(Array.get(array, 1));

多维数组:Java反射没有提供能够直接访问多维数组元素的API,但你可以把多维数组当成数组的数组处理。

5.2 枚举

枚举隐式继承自java.lang.EnumEnum继承自Object

结论

Java反射机制是Java语言的一个重要特性,它提供了一种动态访问和操作对象的能力。虽然它有性能和安全上的考量,但在需要动态性和灵活性的场景下,反射是一个不可或缺的工具。理解和掌握反射机制,可以帮助我们编写出更加灵活和强大的Java程序。


http://www.mrgr.cn/news/66808.html

相关文章:

  • 基于python深度学习的交通标志图像识别设计与实现,卷积神经网络(CNN)作为主要架构
  • LabVIEW离心泵性能优化测试系统
  • 模板
  • yolo训练中过拟合、欠拟合判断和两者的解决方法
  • 串的定义和基本操作
  • Linux下Nginx的安装与使用
  • Vue2基础
  • 【AD】2-5 已存在原理图自动生成元件库
  • 国旅客运标杆!苏州金龙新V系客车打造西江景区直通车新纪元
  • 论文阅读--基于MLS点云语义分割和螺栓孔定位的盾构隧道错位检测方法
  • Python 使用 Selenium 如何抓取动态网页
  • ssm061基于SSM框架的个人博客网站的设计与实现+vue(论文+源码)_kaic
  • rabbitMQ RabbitTemplate 发送消息
  • android 使用xml设置背景图片和圆角
  • Centos7 搭建 Java Web 开发环境
  • 从 ES Kafka Mongodb Restful ... 取到 json 之后
  • HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)本地搜索方案概述
  • 变异凯撒(Crypto)
  • 【区块链】深入理解智能合约 ABI
  • JVM知识点大全(未完...)
  • 【Golang】Slice切片学习+实验代码
  • 全面解析:网络协议及其应用
  • SQLAlchemy 介绍与实践
  • 《XGBoost算法的原理推导》12-2 t轮迭代中对样本i的预测值 公式解析
  • DICOM标准:DICOM图像核心属性概念详解——关于参考帧、病人位置、病人方位、图像位置和图像方向、切片位置、图像像素等重要概念解析
  • 双十一热销中 Witsbb健敏思小蓝条钙镁锌霸榜品类TOP1,行业引领者