关于Java反射

news2024/11/24 1:00:51

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射概念

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

Class类

阅读API的Class类得知,Class没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass方法自动构造的。

/**
 * 获取一个class类文件对象的三种方式
 * 1、对象获取
 * 2、类名获取
 * 3、Class类的静态方法获取
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //1、对象获取,通过父类方法getClass获取
        Person p = new Person();
        Class pC01 = p.getClass();

        //2、类名获取
        //每个类型,包括基本和引用,都会赋予这个类型一个静态属性class
        Class pC02 = Person.class;

        //3、Class类的静态方法获取
        Class pC03 = Class.forName("com.if010.classloader.Person");

        //疑问:pC01 == pC02 == pC03 ?
        System.out.println(pC01 == pC02); //True
        System.out.println(pC01 == pC03); //True
        System.out.println(pC02 == pC03); //True
    }
}

第三种和前两种的区别,前两种你必须明确Person类型,后面是指定这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了。

获取公共构造方法,创建对象

获取构造方法,步骤如下:

  1. 获取到Class对象
  2. 获取指定的构造方法
  3. 通过构造方法类Constructor中的方法,创建对象
import java.lang.reflect.Constructor;

/**
 * 通过反射获取Class文件中的构造方法,并运行构造方法
 * 运行构造方法创建对象
 *  1. 获取到Class对象
 *  2. 获取指定的构造方法
 *  3. 通过构造方法类Constructor中的方法,创建对象
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class pClass = Class.forName("com.if010.classloader.Person");

        //使用class文件对象,获取类中的构造方法,有两种方式拿取
        //1、getConstructors() 获取class文件中的所有的公共的构造方法
        Constructor[] constructors = pClass.getConstructors();
        for (Constructor c : constructors){
            System.out.println(c);
        }
        //2、getConstructor() 获取class文件中的一个空参构造方法
        Constructor constructor = pClass.getConstructor();
        //运行空参构造器的方法,Constructor类newInstance方法
        Object obj = constructor.newInstance();

        //getConstructor(Class<?>...parameterTypes) 获取class文件中的一个有参构造方法
        Constructor constructor1 = pClass.getConstructor(String.class,int.class);
        //运行有参构造器的方法,Constructor类newInstance方法
        Object obj1 = constructor1.newInstance("zhangsan",19);

        //快捷方法(条件:被反射的类有空参构造方法,且该方法是public)
        Object obj2 = Class.forName("com.if010.classloader.Person").newInstance();
        System.out.println(obj2);
    }
}

获取私有构造方法,创建对象

AccessibleObject 类是 Field、Method 和 Constructor 对象的父类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。常用方法如下:

  • public void setAccessible(boolean flag) throws SecurityException

参数值为true则指示反射的对象在使用时应该取消 Java 语言访问检查。参数值为false则指示反射的对象应该实施 Java 语言访问检查。

获取私有构造方法,步骤如下:

  1. 获取到Class对象
  2. 获取指定的构造方法
  3. 暴力访问, 通过setAccessible(boolean flag)方法
  4. 通过构造方法类Constructor中的方法,创建对象public T newInstance(Object… initargs)
import java.lang.reflect.Constructor;

/**
 * 反射获取私有的构造方法运行
 * 不推荐,破坏了程序的封装性、安全性
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class pClass = Class.forName("com.if010.classloader.Person");

        //getDeclaredConstructors()获取所有的构造方法(包括私有的)
        Constructor[] constructors = pClass.getDeclaredConstructors();
        for (Constructor c : constructors){
            System.out.println(c);
        }

        //getDeclaredConstructor(Class...c)获取指定参数列表的构造方法
        Constructor constructor = pClass.getDeclaredConstructor(int.class,String.class);
        //Constructor类的父类AccessibleObject类setAccessible(boolean flag)方法可以取消访问权限,简称暴力反射
        //如果不取消会报错"IllegalAccessException"
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(19,"zhangsan");
        System.out.println(obj);
    }
}

获取成员变量并使用

在反射机制中,把类中的成员变量使用类Field表示,可通过Class类中提供的方法获取成员变量:

  • 返回一个成员变量
    • public Field getField(String name) 获取指定的 public修饰的变量
    • public Field getDeclaredField(String name) 获取指定的任意变量
  • 返回多个成员变量
    • public Field[] getFields() 获取所有public 修饰的变量
    • public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)
import java.lang.reflect.Field;

/**
 * 反射获取成员变量,并修改值
 * Person类中的成员变量,String name
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class pClass = Class.forName("com.if010.classloader.Person");
        //获取所有的公共成员变量,Class类中的方法getFields()
        Field[] fieldsPub = pClass.getFields();
        for (Field field : fieldsPub){
            System.out.println(field);
        }

        //获取所有的成员变量(包括私有的),Class类中的方法getFields()
        Field[] fieldsAll = pClass.getDeclaredFields();
        for (Field field : fieldsAll){
            System.out.println(field);
        }

        //获取指定的公共成员变量
        //Class类的方法 getField(String name) 传递字符串类型的变量名
        Field fieldPub = pClass.getField("name");
        //修改成员变量的值,void get(Object obj, Object value)
        //Object obj 必须有对象的支持, Object value修改后的值
        Object o = pClass.newInstance();
        fieldPub.set(o, "zhangsan");

        //获取指定的私有成员变量(不推荐,会破坏封装性和安全性)
        //Class类的方法 getDeclaredField(String name) 传递字符串类型的变量名
        Field fieldAll = pClass.getDeclaredField("age");
        //暴力反射,取消访问权限检查,不取消会报错"IllegalAccessException"
        fieldAll.setAccessible(true);
        fieldAll.set(o, 19);

        System.out.println(o);
    }
}

获取成员方法并使用

获取成员方法,步骤如下:

  1. 获取Class对象
  2. 获取构造方法
  3. 通过构造方法,创建对象
  4. 获取指定的方法
  5. 执行找到的方法public Object invoke(Object obj, Object… args),执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。
import java.lang.reflect.Method;

/**
 * 反射获取成员方法并运行
 *
 */
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class pClass = Class.forName("com.if010.classloader.Person");
        //获取class文件中的公共成员方法(包括继承的)
        Method[] methods = pClass.getMethods();
        for (Method m : methods){
            System.out.println(m);
        }

        //获取class文件中指定的空参公共成员方法
        //Method getMethod(String methodName, Class...c)
        //String methodName 方法名,Class...c 参数列表
        Method method = pClass.getMethod("eat");
        //使用Method类方法Object invoke(Object obj, Object...o) 运行class文件中的方法
        method.invoke(pClass.newInstance());

        //获取class文件中指定的有参公共成员方法
        Method method1 = pClass.getMethod("speak", String.class);
        Object speak = method1.invoke(pClass.newInstance(), "Hello呀!");
        System.out.println(speak);

        //获取class文件中指定的空参私有成员方法(不推荐,会破坏封装性和安全性)
        Method method2 = pClass.getDeclaredMethod("work");
        //暴力反射,取消访问权限检查,不取消会报错"IllegalAccessException"
        method2.setAccessible(true);
        method2.invoke(pClass.newInstance());
    }
}

泛型擦除

将已存在的ArrayList集合中添加一个字符串数据,如何实现呢?

其实程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。那么,我们可以通过反射技术,来完成向有泛型约束的集合中,添加任意类型的元素。

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * 定义一个集合类,固定类型String
 * 要求向集合中加入int类型
 *
 * 反射方式,获取出集合ArrayList类的class文件对象
 * 通过class文件对象,调用add方法
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        ArrayList<String> arrayList = new ArrayList<String>();
        arrayList.add("hello");
        arrayList.add("world");

        //获取出集合ArrayList类的class文件对象
        Class c = arrayList.getClass();
        //通过ArrayList类的class文件对象获取add方法
        Method method = c.getMethod("add", Object.class);
        //使用invoke运行add方法
        method.invoke(arrayList, 100);
    }
}

反射配置文件

通过反射配置文件,运行配置文件中指定类的对应方法,读取Peoperties.txt文件中的数据,通过反射技术,来完成Person对象的创建。

import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 读取class.properties文件中的数据,通过反射技术,来完成Person对象的创建
 *
 * class.properties文件内容:
 * ClassName=com.if010.classloader.Person
 * MethodName=eat
 */
public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //通过IO流读取配置文件
        FileReader fileReader = new FileReader("./Test/class.properties");
        Properties classPropertie = new Properties();
        classPropertie.load(fileReader);
        fileReader.close();
        String className = classPropertie.getProperty("ClassName");
        String methodName = classPropertie.getProperty("MethodName");


        //开始反射
        //1、获取Person.class 字节码文件对象
        Class c = Class.forName(className);
        //2、获取构造方法
        Method method = c.getMethod(methodName);
        //3、创建对象
        Object object = c.newInstance();
        //4、运行方法
        method.invoke(object);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MyBatis Plus-个人笔记

前言 学习视频 尚硅谷-Mybatis-Plus教程学习主要内容 本文章记录尚硅谷-Mybatis-Plus教程内容&#xff0c;只是作为自己学习笔记&#xff0c;如有侵扰请联系删除 一、MyBatis-Plus简介 1、简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis的增强工具&#…

BGP基础实验建邻+宣告实验

实验题目如下&#xff1a; 实验拓扑如下&#xff1a; 实验要求如下&#xff1a; 【1】除R5的5.5.5.0环回外&#xff0c;其他所有的环回均可互相访问 实验思路如下&#xff1a; &#xff08;1&#xff09;合理的IP配置 &#xff08;2&#xff09;合理的BGP配置 &#xff08;…

监控Kubernetes Node组件的关键指标

所有的 Kubernetes 组件&#xff0c;都提供了 /metrics 接口用来暴露监控数据&#xff0c;Kube-Proxy 也不例外。通过 ss 或者 netstat 命令可以看到 Kube-Proxy 监听的端口&#xff0c;一个是 10249&#xff0c;用来暴露监控指标&#xff0c;一个是 10256 &#xff0c;作为…

【IC萌新虚拟项目】代码覆盖率收集与反馈

关于整个虚拟项目&#xff0c;请参考&#xff1a; 【IC萌新虚拟项目】Package Process Unit项目全流程目录_尼德兰的喵的博客-CSDN博客 前言 实际参与过项目的同学一定对质量活动这四个字深恶痛绝&#xff0c;项目进入质量活动阶段时&#xff0c;意味着RTL的时序和面积功耗等主…

【算法训练营】队列 合集(1)

&#x1f4cd;前言 本篇将学习queue的OJ题并学习queue的基础知识。 &#x1f57a;作者&#xff1a; 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 &#x1f3c7;码字不易&a…

Linux Day07

一、僵死进程 1.1僵死进程产生的原因 子进程先于父进程结束, 而父进程没有获取子进程退出码&#xff0c;释放子进程占用的资源&#xff0c;此时子进程将成为一个僵死进程。 在第一个框这里时父进程子进程都没有结束&#xff0c;显示其pid 父进程是2349&#xff0c;子进程是235…

nnU-Net 终极指南

一、说明 了解最先进的nnU-Net以及如何将其应用于您自己的数据集所需的一切。使用nnU-Net&#xff0c;这是语义图像分割中非常强大的基线。在本指南中&#xff0c;您将&#xff1a; 对nnU-Net的主要贡献进行简要概述。了解如何将 nnU-Net 应用于您自己的数据集。 但是&#xff…

【C++】set 和 map 简单了解使用

文章目录 关联式容器set 和 multisetmap 和 multimap 关联式容器 set 和 multiset map 和 multimap

【福建事业单位-资料分析】04 倍数、特殊增长率

【福建事业单位-资料分析】04 倍数、特殊增长率 一、倍数1.1现期倍数1.2 基期倍数总结 二、特殊增长率2.1 间隔增长率间隔倍数和间隔基期&#xff08;都要先求得间隔增长率r&#xff09; 2.2 年均增长率年均增长率的比较年均增长率计算-居中代入 2.3 混合增长率总结 三、总结 一…

Git入门到精通——保姆级教程(涵盖GitHub、Gitee、GitLab)

文章目录 前言一、Git1.Git-概述1.1.Git-概述-版本控制介绍1.2.Git-概述-分布式版本控制VS集中式版本控制1.3.Git-概述-代码托管中心1.4.Git-概述-安装和客户端的使用 2.Git-命令(常用命令)2.1.Git-命令-设置用户签名2.2.Git-命令-初始化本地库2.3.Git-命令-查看本地库状态2.4.…

goto语句

goto语句也称为无条件转移语句。 goto的语法&#xff1a;goto 语句标号; 语句标号的语法&#xff1a;语句标号: 如果在程序中使用了goto&#xff0c;程序的流程将跳转到语句标号的位置&#xff0c;并执行它后面的代码。 其中语句标号是按标识符规定书写的符号&#xff0c;放…

计算机网络实验2:网络嗅探

文章目录 1. 主要教学内容2. Wireshark介绍3. Wireshark下载4. 使用Wireshark捕获包4.1 选择网卡4.2 停止抓包4.3 保存数据 5. Wireshark的过滤规则6. Wireshark实例 1. 主要教学内容 实验内容&#xff1a;安装、学习使用网络包分析工具Wireshark。所需学时&#xff1a;1。重难…

信息安全:访问控制技术原理与应用.

信息安全&#xff1a;访问控制技术原理与应用. 访问控制是网络信息系统的基本安全机制。访问控制是指对资源对象的访问者授权、控制的方法及运行机制。访问者又称为主体&#xff0c;可以是用户、进程、应用程序等&#xff1b;而资源对象又称为客体&#xff0c;即被访问的对象&…

搞定libstdc++.so.6 version GLIBCXX_3.4.21 not found

一、问题&#xff1a; 今天在安装whisper的时候&#xff0c;突然间报了这样一个错误&#xff1a; OSError: Could not load shared object file: libllvmlite.so Errors were: [OSError("/lib64/libstdc.so.6: version GLIBCXX_3.4.21 not found (required by /opt/con…

【直接收藏】前端 VUE 高阶面试题(一)

1.说说vue动态权限绑定渲染列表&#xff08;权限列表渲染&#xff09; 首先请求服务器,获取当前用户的权限数据,比如请求 this.$http.get("rights/list"); 获取到权限数据之后,在列表中使用v-if v-if-else的组合来展示不同的内容 <template><div><…

cpu的架构

明天继续搞一下cache,还有后面的, 下面是cpu框架图 开始解释cpu 1.控制器 控制器又称为控制单元&#xff08;Control Unit&#xff0c;简称CU&#xff09;,下面是控制器的组成 1.指令寄存器IR:是用来存放当前正在执行的的一条指令。当一条指令需要被执行时&#xff0c;先按…

nginx基于主机和用户访问控制以及缓存简单例子

一.基于主机访问控制 1.修改nginx.conf文件 2.到其他主机上测试 &#xff08;1&#xff09;191主机 &#xff08;2&#xff09;180主机 二.基于用户访问控制 1.修改nginx.conf文件 2.使用hpasswd为用户创建密码文件&#xff0c;并指定到刚才指定的密码文件webck 3.测试…

腾讯云轻量应用服务器和云服务器有什么区别?

腾讯云轻量服务器和云服务器有什么区别&#xff1f;为什么轻量应用服务器价格便宜&#xff1f;是因为轻量服务器CPU内存性能比云服务器CVM性能差吗&#xff1f;轻量应用服务器适合中小企业或个人开发者搭建企业官网、博客论坛、微信小程序或开发测试环境&#xff0c;云服务器CV…

算法套路二十——单调栈

算法套路二十——单调栈 单调栈是一种特殊的数据结构&#xff0c;用于解决与元素的相对大小有关的问题。它是一个栈&#xff0c;但其中的元素以单调递增或单调递减的顺序排列&#xff0c;用于处理与相对大小有关的问题。 算法示例&#xff1a;下一个更大元素 给定一个数组 nu…

C语言指针之 进阶

前言 今天来较为深入的介绍一下指针&#xff0c;希望大家能有所收获&#xff5e; 那么&#xff0c;先进行一些简单的基础知识复习吧。 字符指针 格式&#xff1a;char * 补充&#xff1a; 表达式“abcdef”的值是首字符a的地址 所以当像下面这么使用时&#xff0c;它的含…