java每日一记 —— 谈谈反射

这应该是基础吧

  • 1.先来说点前置知识:类的加载机制
  • 2.以自己的方式来谈反射的概念
  • 3.获取class的三种方式
    • 3.1.通过已知的类型获取class
    • 3.2.通过实例对象获取class
    • 3.3.通过Class.forName获取全路径指定类名的class
  • 4.整理了一下API:坦言说🪡累
  • 5.现场玩一把
  • 6.反射机制应用的场景

本篇代码在jdk11中测试通过

1.先来说点前置知识:类的加载机制

1.博主是这样理解的:Java 类的加载机制就是将类从字节码转换为运行时实例的过程(好吧!!!我是来搞笑的😱😱😱😱)

2.回归正题:Java 类的加载机制是一个动态过程,由 Java 虚拟机 (JVM) 自动完成

一般流程如下:

  • 加载:将类从磁盘或其他数据源加载到 JVM 内存中
  • 验证:确保类有效,并符合语义要求
  • 准备:给类变量分配内存,并设置类变量的默认值
  • 解析:将常量池中的符号引用替换为直接引用
  • 初始化:给类变量赋值,并调用类构造函数

来一张小破图:
在这里插入图片描述

开个小玩笑:我怎么越看越像上高速公路的一个过程??
加载?好像是从四面八方来的车要进入收费站入口
验证?怎么看都是收费站的要判断你是否符合上高速的要求啊?
准备?这个有点像给你发的通行卡中记录了你的信息?
解析?你进入高速匝道后的指示牌给你直接引用到正确的路线?
初始化?这个不就是进入高速后给车加油门,并且打开我们的bgm?

3.总结一下:其实吧每个阶段都涉及 JVM 内部的操作,这只是为了确保类的安全性和可用性。因此,在运行时可以通过反射轻松访问 Java 类的信息

特别注意:今天的主角不是类加载机制,这些只是根据经验写了点

2.以自己的方式来谈反射的概念

1.定义:Java反射是一种允许我们在程序运行时访问和修改其自身行为的技术。它允许我们在运行时检查和修改程序的行为,而不需要重新编译或启动程序

2.面试时我如果按照定义说,面试官肯定肯说我背了八股,所以我用自己的理解说下反射的定义吧:

  • 通俗说法:Java反射是一种能够在运行时检查和修改程序自身行为的能力。它可以让我们在不重新编译或重启应用程序的情况下,对程序的行为进行更改。例如,我们可以使用反射来动态地改变一个类的方法或者字段值,或者动态地创建和访问类的实例

我来以生活的方式来说:

首先,让我们从一个简单的例子开始。假设我们正在准备一顿晚餐,并且想要制作一道美味的意大利面。在烹饪过程中,我们需要了解各种食材的特性,比如面条需要煮多久才能达到最佳口感,番茄酱应该如何调配等等。这就像是我们在编程时需要了解每个类和方法的功能一样。

现在,想象一下如果我们有一本食谱,它不仅告诉我们如何做菜,还告诉我们可以用哪些不同的食材来替代原本的食材,甚至还可以告诉我们每种食材有哪些未知的特性和用途。这就是Java反射的概念

Java反射允许我们在运行时检查和修改程序的行为。就像我们的食谱一样,它提供了一种方式来查看和操作代码的各种元素,如类、接口、字段和方法。我们可以利用这些信息来创建新的对象、调用方法、改变字段值等

3.new 和反射的对比

在这里插入图片描述
4.java相关类介绍

类名描述
Class<T>代表类的实体,在运行的Java应用程序中表示类或者接口
Field类的成员变量(成员变量也称为类的属性)
Method类的方法
Constructor<T>类的构造方法

3.获取class的三种方式

3.1.通过已知的类型获取class

1.上代码

public Class<User> getUser01(){Class<User> clazz = User.class;return clazz;
}

2.运行结果
在这里插入图片描述

3.2.通过实例对象获取class

1.上代码

public Class<User> getUser02(){User user = new User();Class<?> clazz = user.getClass();return (Class<User>)clazz;
}

2.运行结果
在这里插入图片描述

3.3.通过Class.forName获取全路径指定类名的class

1.上代码

public static Class<User> getUser03()throws ClassNotFoundException{Class<?> clazz = Class.forName("com.andy.fan_she.pojo.User");return (Class<User>)clazz;
}

2.运行结果
在这里插入图片描述

4.整理了一下API:坦言说🪡累

1.Class常用操作方法

// 获取所有的构造方法 (private和public都可以)
public Constructor<?>[] getDeclaredConstructors()// 获取特定的构造方法 (private和public都可以)
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)// 获取类的父类
public native Class<? super T> getSuperclass()// 获取类实现的接口
private Class<?>[] getInterfaces(boolean cloneArray)// 获取在类内定义的内部类或接口
public Class<?>[] getDeclaredClasses()// 获取所有的方法
public Method[] getDeclaredMethods() throws SecurityException// 根据方法名和参数获得特定的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)// 获取类型的定义的所有属性
public Field[] getFields()// 根据属性命名获得特定的Field
public Field getField(String name)

2.Method常用的操作方法

// 获得方法的放回类型
public Class<?> getReturnType()// 获得方法的传入参数类型
public Class<?>[] getParameterTypes()// obj是实例对象,args是方法,反过来由Method控制对象的方法调用
public Object invoke(Object obj, Object... args)

3.Field常用的操作方法

// 属性与obj相等则返回true
public boolean equals(Object obj)// 获得obj中对应的属性值
public Object get(Object obj)// 设置obj中对应属性值
public void set(Object obj, Object value)

4.Constructor

// 根据传递的参数创建类的对象:initargs 构造方法参数
public T newInstance(Object... initargs) 

⚠️注意啦!!!注意啦!!!⚠️

  • 从Java 11开始,newInstance()方法已被弃用,因为它存在一定的安全风险。现在推荐使用Class.getDeclaredConstructor().newInstance()的方式来替代

  • 在Java 11及更高版本中,如果没有显式声明默认构造函数,那么默认情况下是不会生成无参数构造函数的。因此,如果要调用newInstance()方法,则需要确保类具有可访问的无参数构造函数

5.现场玩一把

来个测试对象类

/*** @author Andy* @version 0.0.1*/
public class User implements Serializable {private Integer id;private String username;private string password;private String password;public User(Integer id, String username, String password) {this.id = id;this.username = username;this.password = password;}...getter/setter}

1.根据class创建对象

public User getUser01() throws Exception {Class<User> clazz = User.class;Constructor<User> constructor = clazz.getConstructor(Integer.class, String.class, String.class);constructor.setAccessible(true);User user = constructor.newInstance(1, "andy", "123456");return user;
}

2.由class获取Field,并操作实例的属性

public static User getUser02() throws Exception{Class<User> clazz = User.class;Constructor<User> constructor = clazz.getConstructor(Integer.class, String.class, String.class);constructor.setAccessible(true);User user = constructor.newInstance(1, "andy", "123456");// 主要是这块逻辑Field declaredField = clazz.getDeclaredField("id");declaredField.setAccessible(true);declaredField.set(user, 2);return user;
}

3.由class获取Method,并反射调用实例方法

// 在pojo中加入:
public void getTestUser(String name){System.out.println("测试反射方法:" + name);
}// 测试方法:
public static void getUser03() throws Exception {Class<User> clazz = User.class;Constructor<User> constructor = clazz.getConstructor(Integer.class, String.class, String.class);constructor.setAccessible(true);User user = constructor.newInstance(1, "andy", "123456");//主要逻辑Method declaredMethod = clazz.getDeclaredMethod("getTestUser", String.class);declaredMethod.setAccessible(true);declaredMethod.invoke(user, "Andy测试");
}

6.反射机制应用的场景

  • 动态拓展:假设有同一组类是实现相同的接口,并且类的加载方式不限制。当我们需要那种具体类实现的功能时,只需加载.class文件,并获取对应的Class对象。可以由Class或者Constructor实例化对象instance;根据接口定义,可以获取Class里的某一方法Method,并配合instance反射调用功能方法
  • Spring的IOC就是基于反射机制实现
  • JDK的动态代理

博主记得之前写过一个动态代理的博客,今天特地的跑去看了下🪡的是反射机制。有兴趣的可以看下:https://blog.csdn.net/weixin_44702984/article/details/130278266?spm=1001.2014.3001.5502

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

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

相关文章

开源网安解决方案荣获四川数实融合创新实践优秀案例

​11月16日&#xff0c;2023天府数字经济峰会在成都圆满举行。本次峰会由四川省发展和改革委员会、中共四川省委网络安全和信息化委员会办公室、四川省经济和信息化厅等部门联合指导&#xff0c;聚焦数字经济与实体经济深度融合、数字赋能经济社会转型发展等话题展开交流研讨。…

(c语言进阶)内存函数

一.memcpy(void* dest,void* src,int num) &#xff0c;操作单位为字节&#xff0c;完成复制且粘贴字符串 1.应用 #include <stdio.h> #include<string.h> int main() {int arr1[] { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] { 0 };memcpy(arr2, arr1, 20);//从…

C语言--统计一行字符串的单词个数, 单词用非字母分割.例如“ab235adg 456ad“被认为是3个单词.

一.题目描述 统计一行字符串的单词个数, 单词用非字母分割. 例如"ab235adg 456ad"被认为是3个单词. 二.思路分析 本题的主要难点在于如何判断有一个单词呢&#xff0c;当然遍历字符串是必须的。下面给出两种不同的思路&#xff1a; 一.当前是字母&#xff0c;下一个…

腾讯智影数字人工具

腾讯智影数字人工具 腾讯智影数字人的形象风格多样&#xff0c;包括写实、卡通等&#xff0c;可以满足不同年龄层观众的喜好。同时&#xff0c;腾讯智影数字人也提供了灵活的驱动方案&#xff0c;可以通过文本或配音直接生成视频&#xff0c;并支持数字人做出与视频一样的动作…

【Unity小技巧】图片使用的一些常见问题

文章目录 前言Button不规则按钮点击空白区域不响应点击事件1. 设置资源参数2. 代码设置按钮Image的alphaHitTestMinimumThreshold3. 解释&#xff1a;4. 效果 Unity Image 原图比例控制方法一 Preserve Aspect1. 设置勾选Preserve Aspect&#xff08;保持长宽比&#xff09;&am…

头歌 MySQL数据库 - 初识MySQL

本章内容是为了完成老师布置的作业&#xff0c;同时也是为了以后考试的时候方便复习。 数据库部分一条一条的写&#xff0c;可鼠标手动粘贴&#xff0c;除特定命令外未分大小写。 第1关&#xff1a;创建数据库 在操作数据库之前&#xff0c;需要连接它&#xff0c;输入命令&a…

基于DOTween插件实现金币飞行到指定位置功能

文章目录 前言一、DOTween是什么&#xff1f;二、使用步骤1.导入DOTween插件在Unity官方插件商店找到DOTween插件导入DOTween插件启用DOTween插件 2.代码逻辑金币飞行代码控制飞行效果代码 3.物体配置1.物体上装配CoinEffect脚本2.在金币预制体上装配FlyControl脚本 三、效果展…

【Java SE】继承

学习完了类之后&#xff0c;我们将继续学习一个Java中的重点内容“继承” 继承 1.1 为什么需要继承 举例&#xff1a; 在Cat类中和Dog类中我们发现有很多一样的地方&#xff0c;这样写太浪费空间和内存了 我们可以把它相同的地方都用一个类来表示&#xff0c;并且使用它1.2 继…

IPSecGRE

IPSec&GRE 手工方式建立IPSec隧道组网实验拓扑配置步骤第一步配置IP地址第二步配置静态路由第三步配置IPSec 抓包测试 GRE Over IPSec功能的配置组网实验拓扑配置命令 配置GRE使用静态路由组网图实验拓扑配置步骤1.配置RouterA2.配置RouterB3.配置RouterC4.验证配置结果 手…

Wordpress页面生成器:Elementor 插件制作网站页面教程(图文完整)

本文来教大家怎么使用Wordpress Elementor页面编辑器插件来自由创建我们的网页内容。很多同学在面对建站的时候,一开始都是热血沸腾信心满满的,等到实际上手的时候就会发现有很多问题都是无法解决的,希望本篇Elementor插件使用指南能够帮助到你。 Wordpress Elementor页面编…

git拉取普通idea Java项目module没有build的问题

在不断完成一个项目的时候&#xff0c;会有不断新加的module&#xff0c;我们用git拉取时会发生没有识别新module的情况。 解决方法是右键项目名称&#xff0c;然后点击Open Module Settings 接下来&#xff0c;点击Module&#xff0c;加号&#xff0c;新建Module的名字就是在g…

LeetCode47-全排列II-剪枝逻辑

参考链接: &#x1f517;:卡尔的代码随想录:全排列II 这里第一层,used只有一个元素为1,代表只取出了1个元素作为排列,第二层used有两个元素为1,代表取出了2个元素作为排列,因为数组有序,所以重复的元素都是挨着的,因此可以使用如下语句去重. 其中visit[i-1]False的话,就是代表…