Java—反射机制详解

介绍反射

反射的基本概念

反射(Reflection)是Java语言中的一种机制,它允许程序在运行时检查和操作类、接口、字段和方法等类的内部结构。通过反射,你可以在运行时获取类的信息,包括类的构造器、字段、方法等,并且可以在运行时动态地创建对象、调用方法、访问或修改字段。

反射的核心类和接口

Java反射机制主要涉及以下几个核心类和接口:

  • Class:表示一个类的字节码文件对象,通过它可以获取类的所有信息。
  • Constructor:表示类的构造器对象,通过它可以获取构造器的参数、修饰符等信息,并可以用来创建类的实例。
  • Field:表示类的成员变量对象,通过它可以获取字段的类型、修饰符等信息,并可以用来访问或修改字段的值。
  • Method:表示类的方法对象,通过它可以获取方法的参数、返回值类型、修饰符等信息,并可以用来调用方法。

反射的优点

  • 可扩展性:反射允许程序在运行时动态地加载和使用类,这使得程序具有更好的可扩展性。例如,可以通过配置文件来加载不同的类,从而实现插件化架构。
  • 类浏览器和可视化开发环境:反射可以帮助IDE等开发工具获取类的详细信息,从而提供更好的代码提示、自动补全等功能。
  • 调试器和测试工具:反射可以帮助调试器和测试工具获取类的内部信息,从而实现更强大的调试和测试功能。

反射的缺点

  • 性能开销:反射操作通常比直接调用方法或访问字段要慢得多,因为反射涉及动态解析,JVM无法对其进行优化。
  • 安全限制:反射可以绕过访问控制,访问私有字段和方法,这可能会导致安全问题。
  • 内部暴露:反射可以访问类的内部实现细节,这可能会导致代码的可移植性和稳定性受到影响。

获取元素

获取类

在反射中,获取类的Class对象是第一步。Class对象代表了类的字节码文件,通过它可以获取类的所有信息。获取Class对象有三种主要方式:

通过类名获取:

Class<?> clazz = Class.forName("com.example.MyClass");

这种方式需要类的全限定名(包名+类名),适用于在运行时动态加载类。

通过对象获取:

MyClass obj = new MyClass();
Class<?> clazz = obj.getClass();

这种方式适用于已经有一个类的实例对象的情况。

通过类字面量获取:

Class<?> clazz = MyClass.class;

这种方式适用于在编译时已经知道类名的情况。

Class类下的常用方法:

  • String getSimpleName():获取类的简单名称(不包括包名)。
  • String getName():获取类的全限定名(包括包名)。
  • T newInstance():创建Class对象关联类的实例对象,底层调用无参构造器。注意:这个方法已经被标记为@Deprecated,建议使用Constructor来创建对象。

获取构造器

获取构造器的方法主要通过Class对象来实现:

获取特定构造器:

  • Constructor getConstructor(Class... parameterTypes):根据参数类型获取某个public修饰的构造器。
  • Constructor getDeclaredConstructor(Class... parameterTypes):根据参数类型获取某个构造器,不关心权限修饰符。

获取所有构造器:

  • Constructor[] getConstructors():获取所有public修饰的构造器。
  • Constructor[] getDeclaredConstructors():获取所有构造器,不关心权限修饰符。

Constructor的常用方法:

  • T newInstance(Object... initargs):使用指定的参数创建类的实例对象。
  • void setAccessible(true):设置访问权限,true表示可以访问私有构造器(暴力反射)。
  • String getName():获取构造器的名称。
  • int getParameterCount():获取构造器的参数数量。
  • Class<?>[] getParameterTypes():获取构造器的参数类型数组。

获取成员变量

获取成员变量的方法主要通过Class对象来实现:

获取特定成员变量:

  • Field getField(String name):根据成员变量名获取public修饰的成员变量。
  • Field getDeclaredField(String name):根据成员变量名获取成员变量,不关心权限修饰符。

获取所有成员变量:

  • Field[] getFields():获取所有public修饰的成员变量。
  • Field[] getDeclaredFields():获取所有成员变量,不关心权限修饰符。

Field的常用方法:

  • void set(Object obj, Object value):给指定对象的成员变量赋值。
  • Object get(Object obj):获取指定对象的成员变量的值。
  • void setAccessible(true):设置访问权限,true表示可以访问私有成员变量(暴力反射)。
  • Class getType():获取成员变量的类型。
  • String getName():获取成员变量的名称。

获取方法

获取方法的方法主要通过Class对象来实现:

获取特定方法:

  • Method getMethod(String name, Class... args):根据方法名和参数类型获取public修饰的方法。
  • Method getDeclaredMethod(String name, Class... args):根据方法名和参数类型获取方法,不关心权限修饰符。

获取所有方法:

  • Method[] getMethods():获取所有public修饰的方法,包括父类的方法。
  • Method[] getDeclaredMethods():获取所有方法,不关心权限修饰符,只获取本类声明的方法。

Method的常用方法:

  • Object invoke(Object obj, Object... args):使用指定的参数调用方法,obj是调用方法的对象,args是方法的参数。

反射示例

package com.example;import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;// 定义接口,用于打招呼
interface Greetable {void greet(); // 实现打招呼的方法
}// 定义一个父类,用于表示动物
class Animal {protected String species; // 动物的种类// 构造函数,初始化动物的种类public Animal(String species) {this.species = species;}// 让动物发出声音public void makeSound() {System.out.println(species + " 发出声音。");}
}// 定义一个子类,继承自Animal,并实现Greetable接口
class Dog extends Animal implements Greetable {private String name; // 狗的名字// 构造函数,初始化狗的名字public Dog(String name) {super("狗");this.name = name;}// 实现打招呼方法,狗用自己的方式打招呼@Overridepublic void greet() {System.out.println(name + " 说:汪汪!");}
}// 用于演示高级反射用法的示例类
public class AdvancedReflectionExample {// 主函数public static void main(String[] args) {try {// 获取Dog类的Class对象Class<?> dogClass = Dog.class;// 获取构造器并创建实例Constructor<?> dogConstructor = dogClass.getConstructor(String.class);Object dogInstance = dogConstructor.newInstance("小白");// 调用父类的方法Method makeSoundMethod = dogClass.getSuperclass().getDeclaredMethod("makeSound");makeSoundMethod.invoke(dogInstance);// 调用接口方法Method greetMethod = dogClass.getDeclaredMethod("greet");greetMethod.invoke(dogInstance);// 使用反射获取和修改私有字段Field nameField = dogClass.getDeclaredField("name");nameField.setAccessible(true);System.out.println("更新前的名字: " + nameField.get(dogInstance));nameField.set(dogInstance, "小黑");System.out.println("更新后的名字: " + nameField.get(dogInstance));// 创建一个泛型列表并添加Dog对象List<Dog> dogList = new ArrayList<>();dogList.add((Dog) dogInstance);System.out.println("狗狗列表包含: " + dogList.size() + " 只狗。");} catch (Exception e) {e.printStackTrace();}}
}

暴力反射与泛型约束的破坏

泛型在编译阶段提供类型安全,但在运行时被擦除,反射则允许绕过这些安全检查。

核心点:

封装性破坏:通过反射可以访问和修改私有字段和方法,导致原本受保护的对象状态被随意改变。

import java.lang.reflect.Field;class Person {private String name;public Person(String name) {this.name = name;}public String getName() {return name;}
}public class ReflectionEncapsulationDemo {public static void main(String[] args) {Person person = new Person("Alice");// 使用反射访问私有字段try {Field nameField = Person.class.getDeclaredField("name");nameField.setAccessible(true);  // 允许访问私有字段// 修改私有字段的值nameField.set(person, "Bob");// 输出修改后的值System.out.println("修改后的名字: " + person.getName());} catch (Exception e) {e.printStackTrace();}}
}

泛型约束消失:由于泛型类型信息在运行时不可用,使用反射可以插入不符合泛型限制的对象,可能引发类型错误。

package com.example;import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;public class GenericReflectionDemo {public static void main(String[] args) {// 创建一个存储 Double 类型的 ListList<Double> scores = new ArrayList<>();scores.add(99.3);scores.add(199.3);scores.add(89.5);// 使用反射插入一个不符合泛型的字符串try {Class<?> clazz = scores.getClass();Method addMethod = clazz.getDeclaredMethod("add", Object.class);addMethod.invoke(scores, "字符串");  // 插入一个不符合泛型的数据// 输出结果,包含了不符合类型的数据System.out.println("List 内容: " + scores);// List 内容: [99.3, 199.3, 89.5, 字符串]} catch (Exception e) {e.printStackTrace();}}
}

虽然反射可以带来灵活性,但在生产代码中应谨慎使用,以避免引入潜在的错误和安全隐患。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/430988.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在 Windows 上运行 Vue 项目时解决 ‘NODE_OPTIONS‘ 错误

在 Windows 上运行 Vue 项目时解决 ‘NODE_OPTIONS’ 错误 在 Windows 系统上启动 Vue 项目时&#xff0c;遭遇报错。具体报错信息如下&#xff1a; ‘NODE_OPTIONS‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。这个错误通常意味着 Windows 系统无法识…

机器翻译之创建Seq2Seq的编码器、解码器

1.创建编码器、解码器的基类 1.1创建编码器的基类 from torch import nn#构建编码器的基类 class Encoder(nn.Module): #继承父类nn.Moduledef __init__(self, **kwargs): #**kwargs&#xff1a;不定常的关键字参数super().__init__(**kwargs)def forward(self, X, *args…

基于SpringBoot+Vue+MySQL的美食点餐管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 在数字化快速发展的今天&#xff0c;餐饮行业也迎来了转型升级的重要机遇。传统餐饮管理方式面临效率低下、顾客体验不佳等问题。为此&#xff0c;开发一款基于SpringBootVueMySQL架构的美食点餐管理系统显得尤为重要。该系统旨…

【可图(Kolors)部署与使用】大规模文本到图像生成模型部署与使用教程

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 1.Kolors 简介 1.1.什么是Kolors&#xff1f; 开发团队 Kolors 是由快手 Kolors 团队…

网页护眼宝——全方位解析 Chrome Dark Reader 插件

网页护眼宝——全方位解析 Chrome Dark Reader 插件 1. 基本介绍&#xff1a;Chrome 插件的力量与 Dark Reader 的独特之处 随着现代浏览器的功能越来越强大&#xff0c;Chrome 插件为用户提供了极大的定制化能力。从广告屏蔽、性能优化到页面翻译&#xff0c;Chrome 插件几乎…

视频监控相关笔记

一、QT 之 QTreeWidget 树形控件 Qt编程指南&#xff0c;Qt新手教程&#xff0c;Qt Programming Guide 一个树形结构的节点中的图表文本 、附带数据的添加&#xff1a; QTreeWidgetItem* TourTreeWnd::InsertNode(NetNodeInfo node, QTreeWidgetItem* parent_item) { // …

C++: unordered系列关联式容器

目录 1. unordered系列关联式容器1.1 unordered_map1.2 unordered_set 2. 哈希概念3. 哈希冲突4. 闭散列5. 开散列 博客主页: 酷酷学 感谢关注!!! 正文开始 1. unordered系列关联式容器 在C98中&#xff0c;STL提供了底层为红黑树结构的一系列关联式容器&#xff0c;在查询时…

2024 天池云原生编程挑战赛决赛名单出炉,冠军来自中山大学、昆仑数智战队

9 月 20 日&#xff0c;2024 天池云原生编程挑战赛决赛答辩完美落幕&#xff0c;12 支进入决赛的团队用精彩的答辩&#xff0c;为历时 3 个月的大赛画下了圆满的句号。其中&#xff0c;来自中山大学的陈泓仰以及来自昆仑数智的冉旭欣、沈鑫糠、武鹏鹏&#xff0c; 以出色的方案…

[深度学习]神经网络

1 人工神经网络 全连接神经网络 2 激活函数 隐藏层激活函数由人决定输出层激活函数由解决的任务决定: 二分类:sigmoid多分类:softmax回归:不加激活(恒等激活identify)2.1 sigmoid激活函数 x为加权和小于-6或者大于6,梯度接近于0,会出现梯度消失的问题即使取值 [-6,6] ,…

乌克兰因安全风险首次禁用Telegram

据BleepingComputer消息&#xff0c;乌克兰国家网络安全协调中心 &#xff08;NCCC&#xff09; 以国家安全为由&#xff0c;已下令限制在政府机构、军事单位和关键基础设施内使用 Telegram 消息应用程序。 这一消息通过NCCC的官方 Facebook 账号对外发布&#xff0c;在公告中乌…

kubernetes网络(二)之bird实现节点间BGP互联的实验

摘要 上一篇文章中我们学习了calico的原理&#xff0c;kubernetes中的node节点&#xff0c;利用 calico 的 bird 程序相互学习路由&#xff0c;为了加深对 bird 程序的认识&#xff0c;本文我们将使用bird进行实验&#xff0c;实验中实现了BGP FULL MESH模式让宿主相互学习到对…

AI大模型日报#0923:李飞飞创业之后首个专访、华为云+腾讯音乐发布昇腾适配方案

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE-4.0-8K-latest&#xff09;、“智谱AI”&#xff08;glm-4-0520&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅…

深兰科技陈海波应邀出席2024长三角论坛暨虹桥人才创新发展大会

近日&#xff0c;以“人才引领 联动共融——国际化创新与长三角协同”为主题的“2024长三角人才发展论坛暨虹桥人才创新发展大会”在上海国际会议中心隆重举行。上海市委常委、组织部部长、市委人才办主任张为应邀出席并做大会致辞。 深兰科技创始人、董事长陈海波作为特邀企业…

数据结构强化(直播课)

应用题真题分析&备考指南 (三)线性表的应用 (六)栈、队列和数组的应用 &#xff08;四&#xff09;树与二叉树的应用 1.哈夫曼&#xff08;Huffman&#xff09;树和哈夫曼编码 2.并查集及其应用&#xff08;重要&#xff09; &#xff08;四&#xff09;图的基本应用 …

计算机组成原理(笔记4)

定点加减法运算 补码加法&#xff1a; 补码减法&#xff1a; 求补公式&#xff1a; 溢出的概念 在定点小数机器中,数的表示范围为|&#xff58;|<1。在运算过程中如出现大于1的现象,称为 “溢出”。 上溢&#xff1a;两个正数相加&#xff0c;结果大于机器所能表示的最…

【算法】堆与优先级队列

【ps】本篇有 4 道 leetcode OJ。 目录 一、算法简介 二、相关例题 1&#xff09;最后一块石头的重量 .1- 题目解析 .2- 代码编写 2&#xff09;数据流中的第 K 大元素 .1- 题目解析 .2- 代码编写 3&#xff09;前K个高频单词 .1- 题目解析 .2- 代码编写 4&#xf…

d2l | 目标检测数据集:RuntimeError: No such operator image::read_file

目录 1 存在的问题2 可能的解决方案3 最终的解决方案3.1 方案一&#xff08;我已弃用&#xff09;3.2 方案二&#xff08;基于方案一&#xff09; 1 存在的问题 李沐老师提供的读取香蕉数据集的函数如下&#xff1a; def read_data_bananas(is_trainTrue):""…

yolov10算法原理

文章目录 1. 模型效果2. 模型特点2.1 无NMS训练的一致性双重分配策略 (Consistent Dual Assignments for NMS-free Training)双重标签分配 (Dual Label Assignments)一致匹配度量&#xff08;Consistent Match. Metric&#xff09;一对一分配在一对多结果中的频率 2.2. 效率-准…

C++基础:第一个C++程序

初学C #include<iostream> int main() {std::cout << "Enter two numbers:" << std::endl;int v1 0, v2 0;std::cin >> v1 >> v2;std::cout << "The sum of "<< v1 << " and " << v2&…

Ubuntu磁盘不足扩容

1.问题 Ubuntu磁盘不足扩容 2.解决方法 安装一下 sudo apt-get install gpartedsudo gparted