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

Java基础:反射

目录

    • 一. 简介
    • 二. java.lang.Class类
    • 三. java.lang.reflect包
    • 四. 创建对象
    • 五. 调用方法
    • 六. 调用成员变量

一. 简介

反射是 Java 语言中的一种强大机制,允许程序在运行时动态地获取类的信息、访问类的成员(包括字段、方法和构造函数)以及操作这些成员。通过反射可以实现以下操作:

  1. 在运行时获取类的名称、父类、实现的接口等信息。
  2. 访问和修改对象的私有字段的值。
  3. 调用对象的私有方法。
  4. 在运行时创建类的实例。

反射的主要类和接口包括:

  1. Class 类:表示一个类或接口在 Java 运行时的对象。
  2. Field 类:表示类的字段。
  3. Method 类:表示类的方法。
  4. Constructor 类:表示类的构造函数。

二. java.lang.Class类

java.lang.Class 类在 Java 反射机制中起着核心作用。它用于表示正在运行的 Java 应用程序中的类和接口。通过这个类,可以获取关于类的各种信息,如类的名称、属性、方法、父类、实现的接口等。

以下是 Class 类的一些常见方法和用途:

  1. forName(String className):根据类的全限定名加载并返回对应的 Class 对象
  2. getSimpleName():获取类的简单名称(不包含包名)
  3. getCanonicalName():获取类的规范名称(包含包名)
  4. getSuperclass():获取父类的 Class 对象
  5. getInterfaces():获取实现的接口的 Class 对象数组
  6. getDeclaredFields():获取本类声明的所有字段(包括私有字段)
  7. getFields():获取本类及父类的所有公有字段
  8. getDeclaredMethods():获取本类声明的所有方法(包括私有方法)
  9. getMethods():获取本类及父类的所有公有方法
  10. newInstance():创建类的新实例(调用无参构造函数)
public class ClassExample {public static void main(String[] args) {try {Class<?> clazz = Class.forName("java.util.ArrayList");System.out.println("类的简单名称: " + clazz.getSimpleName());System.out.println("类的规范名称: " + clazz.getCanonicalName());Class<?> superclass = clazz.getSuperclass();System.out.println("父类: " + superclass.getCanonicalName());} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

运行结果:

类的简单名称:ArrayList
类的规范名称:java.util.ArrayList
父类:java.util.AbstractList

总之,Class 类为 Java 程序在运行时动态获取和操作类的信息提供了强大的支持。

三. java.lang.reflect包

java.lang.reflect 包提供了用于反射操作的类和接口,允许在运行时检查和操作类、方法、字段和构造函数等。

以下是该包中的一些重要类和接口:

  1. Field 类:表示类的字段。可以通过它获取和设置字段的值,无论字段是公有、私有还是受保护的。
  2. Method 类:代表类的方法。可以获取方法的名称、参数类型、返回类型,并能够在运行时调用方法。
  3. Constructor 类:表示类的构造函数。可用于获取构造函数的参数类型,并通过它创建类的实例。
  4. Array 类:提供了一些静态方法来操作数组。

使用反射机制虽然强大,但也存在一些潜在的问题。例如,反射可能会破坏封装性,导致代码更难以理解和维护。此外,由于反射需要在运行时进行类型检查和方法调用,可能会带来一定的性能开销。

以下是一个简单的示例,展示如何使用 java.lang.reflect 包中的类获取类的方法信息:

import java.lang.reflect.Method;public class ReflectPackageExample {public static void main(String[] args) {try {Class<?> clazz = Class.forName("YourClassName");Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {System.out.println("方法名: " + method.getName());Class<?>[] parameterTypes = method.getParameterTypes();System.out.print("参数类型: ");for (Class<?> parameterType : parameterTypes) {System.out.print(parameterType.getName() + " ");}System.out.println();}} catch (ClassNotFoundException e) {e.printStackTrace();}}
}

总之,java.lang.reflect 包为 Java 提供了在运行时进行动态类型探索和操作的能力,但应谨慎使用,权衡其带来的灵活性和可能产生的问题。

四. 创建对象

在 Java 中使用反射来创建对象,主要通过以下步骤:

  1. 获取要创建对象的类的 Class 对象。可以通过 Class.forName("全限定类名") 或者 对象的 getClass() 方法来获取。
  2. 获取类的构造函数。使用 getDeclaredConstructor(参数类型列表)getConstructor(参数类型列表) 方法。
  3. 通过构造函数创建对象。使用 newInstance(参数值列表) 方法。

示例代码:

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;public class ReflectionObjectCreation {public static void main(String[] args) {try {// 加载类        Class<?> clazz = Class.forName("YourClassName");// 获取无参构造函数       Constructor<?> constructor = clazz.getConstructor();// 使用无参构造函数创建对象 Object object = constructor.newInstance();// 或者获取有参构造函数,并创建对象     Constructor<?> parameterizedConstructor = clazz.getConstructor(String.class);Object parameterizedObject = parameterizedConstructor.newInstance("Parameter Value");} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException |InvocationTargetException e) {e.printStackTrace();}}
}

需要注意的是,使用反射创建对象可能会导致一些性能开销,并且在实际开发中应谨慎使用,通常用于一些特殊的场景,如依赖注入框架、对象工厂等。

五. 调用方法

在 Java 中使用反射来调用方法,通常按照以下步骤进行:

  1. 获取要操作的类的 Class 对象。
  2. 根据方法名和参数类型获取对应的 Method 对象。
  3. 创建类的实例。
  4. 使用 Method 对象的 invoke 方法来调用方法,并传递实例对象和参数值。

示例代码:

import java.lang.reflect.Method;public class ReflectionMethodInvocation {public static void main(String[] args) {try {// 加载类      Class<?> clazz = Class.forName("YourClassName");// 获取指定方法     Method method = clazz.getMethod("methodName", parameterTypes);// 创建对象实例       Object instance = clazz.newInstance();// 调用方法     method.invoke(instance, parameterValues);} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException |InvocationTargetException e) {e.printStackTrace();}}
}

在上述代码中,您需要将 "YourClassName" 替换为实际的类名,"methodName" 替换为要调用的方法名,parameterTypes 替换为方法参数的类型数组,parameterValues 替换为实际传递的参数值。

使用反射调用方法时要处理可能抛出的各种异常,并且要注意性能和安全性方面的考虑。一般情况下,只有在必要时才使用反射来调用方法,例如在框架或特定的动态场景中。

六. 调用成员变量

在 Java 中使用反射来访问和操作成员变量,可以按照以下步骤进行:

  1. 获取要操作的类的 Class 对象。
  2. 根据成员变量名获取对应的 Field 对象。
  3. 如果成员变量是私有访问权限,需要设置可访问性。
  4. 对成员变量进行读写操作。

示例代码:

import java.lang.reflect.Method;public class ReflectionFieldAccess {public static void main(String[] args) {try {// 加载类      Class<?> clazz = Class.forName("YourClassName");// 获取指定成员变量   Field field = clazz.getDeclaredField("fieldName");// 如果是私有变量,设置可访问性       field.setAccessible(true);// 创建对象实例        Object instance = clazz.newInstance();// 读取成员变量的值       Object value = field.get(instance);System.out.println("Value of the field: " + value);// 设置成员变量的值    field.set(instance, newValue);} catch (ClassNotFoundException | NoSuchFieldException | InstantiationException | IllegalAccessException e) {e.printStackTrace();}}
}

在上述代码中,将 "YourClassName" 替换为实际的类名,"fieldName" 替换为要操作的成员变量名,newValue 替换为要设置的新值。

使用反射访问私有成员变量时,需要设置可访问性,否则会抛出异常。同时,反射操作可能会影响代码的封装性和安全性,应谨慎使用。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 笑谈“八股文”,人生不成文
  • 【Kubernetes】k8s集群的资源发布方式
  • LSPatch制作内置模块应用软件无需root 教你制作内置应用
  • 【Java】深度解析Java的反射机制
  • 后端学习笔记(3)--Maven
  • python爬虫实践
  • 【C++】入门基础知识
  • 用VBA在Word中随机打乱单词表,进行分列
  • (四十一)大数据实战——spark的yarn模式生产环境部署
  • 数据守护者的秘籍:SQL Server数据库备份验证全攻略
  • python实现小游戏——植物大战僵尸(魔改版本)
  • Apache Kylin入门指南
  • 链表篇: 04-寻找两个链表的第一个公共结点
  • [极客大挑战 2019]BuyFlag1
  • A+B V2 51Nod - 3415
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • ES6--对象的扩展
  • Golang-长连接-状态推送
  • JAVA_NIO系列——Channel和Buffer详解
  • Javascripit类型转换比较那点事儿,双等号(==)
  • Javascript编码规范
  • JAVA多线程机制解析-volatilesynchronized
  • java取消线程实例
  • node入门
  • web标准化(下)
  • 从0到1:PostCSS 插件开发最佳实践
  • 基于webpack 的 vue 多页架构
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 一个SAP顾问在美国的这些年
  • 白色的风信子
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ‌‌雅诗兰黛、‌‌兰蔻等美妆大品牌的营销策略是什么?
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (备忘)Java Map 遍历
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (深入.Net平台的软件系统分层开发).第一章.上机练习.20170424
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (转)详解PHP处理密码的几种方式
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (轉)JSON.stringify 语法实例讲解
  • .NET 5.0正式发布,有什么功能特性(翻译)
  • .net core 的缓存方案
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .Net6使用WebSocket与前端进行通信
  • [ C++ ] STL---仿函数与priority_queue
  • [2669]2-2 Time类的定义
  • [ABP实战开源项目]---ABP实时服务-通知系统.发布模式
  • [Android] 240204批量生成联系人,短信,通话记录的APK
  • [Angularjs]asp.net mvc+angularjs+web api单页应用之CRUD操作