IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【JAVA反射】反射的原理及简单使用实例 -> 正文阅读

[Java知识库]【JAVA反射】反射的原理及简单使用实例

反射机制的概要

?JAVA的反射机制,就是可以通过全类名,获取当前类、调用当前类方法,以及获取或修改当前类属性的一个机制。
?总结来说:就是通过类对象来获取类信息的一个途径。
?如示例:若A类无法引用B类的话,但是又要调用B类的方法,其实就可以调用反射获取B类并且执行B类的方法。


通过反射创建类

首先认识类对象 :Class,类对象中中记录了这个类包含了哪些属性、哪些方法、以及有哪些构造方法等信息。
对于Class的话在这里不多做介绍,具体可以看这个博客:类对象详细介绍.

获取Class的方式

// A的全类名为: package.pojo.A
// 首先有以下几种方式获取类对象
Class a = Class.forName("package.pojo.A"); //参数为类的全类名
Class b = A.class;
Class c = new A().getClass();

获取了 Class 类对象之后,就可以通过类对象去调用方法、获取数据等。

通过Class实例化对象

// 通过Class类对象去实例化对象
try {
	// 这里用一种方式去获取Class,也可以用其他方式
	Class a = Class.forName("package.pojo.A");
	// 通过类对象获取默认构造器
	Constructor c = a.getConstructor();
	// 通过构造器调用构造方法完成实例化
	A a1 = (A)c.newInstance();
	// 此时已经获取到A对象,可以通过A对象做后续的事情了
} catch (Exception e) {
	e.printStackTrace();
}

通过反射调用类方法

通过Class去调用类的方法的话,应该是我日常中使用反射用的最多的一个方式了,很多时候无法引入类我都会使用反射去调用所需要的类的方法

通过Class获取类中的方法

我们可以通过 getMethod() 获取到Method对象,来调用类方法
当然还有 getDeclaredMethod() 这两个区别请看下面获取属性的方法即可

// 首先请看Class.getMethod()的源码
/**
	String name: 需要获取的方法的方法名
	Class<?>[] parameterTypes: 调用方法所需的参数的Class数组(可选,无参数则不传递即可)
	includeStaticMethods : 是否获取静态方法(可选)
*/
private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
	// 父接口的方法数组
	MethodArray interfaceCandidates = new MethodArray(2);
	// 获取方法的Method对象
	Method res =  privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
	// 如果不为空,说明从本类或者父类中获取到了root对象的拷贝对象,直接返回
	if (res != null)
		return res;

	// Not found on class or superclass directly
	interfaceCandidates.removeLessSpecifics();
	// 如果没从本类/父类中获取到方法,则从父接口中获取方法
	return interfaceCandidates.getFirst(); // may be null
    }

看完源码之后,其实获取Method对象的就很清晰明了的了,下面是示例

// 首先存在方法为
public String isBigData(String name, Integer number) {
	// 省略方法体
}

// 首先肯定要获取相对应的Class对象
Class a = Class.forName("package.pojo.A");

// 通过调用Class.getMethod()获取方法
// 第一个参数为方法名
// 第二个参数为方法所需参数的Class,因为目前是两个参数,所以要传递一个数组如果方法只有一个参数则传递一个参数即可
// 第三个参数,由于当前方法不是Static,不需要传递
Method isBigDataMethod = a.getMethod("isBigData",  new Class[] { String.class, int.class });

通过Method调用方法

上面已经学习过了如何通过Class获取Method方法对象,此时就可以通过此方法对象去执行方法了

调用方法主要是用到 Method.invoke() 即可

// Method.invoke()源码如下
/**
由于源码解析太长了就不复制进来了,想要看的可以去看源码里面的介绍,目前针对于参数以及返回值做介绍
	* @param obj  调用方法的对象,如调用的是A.isBigData(),此时就传入A对象
	* @param args 用于传递给此调用方法的参数,多个就填多个
	* @return Object 调用的方法的返回值
*/
	@CallerSensitive
    public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
                Class<?> caller = Reflection.getCallerClass();
                checkAccess(caller, clazz, obj, modifiers);
            }
        }
        MethodAccessor ma = methodAccessor;             // read volatile
        if (ma == null) {
            ma = acquireMethodAccessor();
        }
        return ma.invoke(obj, args);
    }

调用方式如下

// 省略之前步骤,获取Method对象
Method isBigDataMethod = a.getMethod("isBigData",  new Class[] { String.class, int.class });

// 由于调用A对象中的方法需要有A对象,所以先创建出来
Class a = Class.forName("package.pojo.A");
Constructor c = a.getConstructor();
Objcet a1 = c.newInstance();

// 直接调用Method.invoke()即可
// 第一个参数调用方法的对象
// 第2,3..个参数,就是调用方法所需的对象
String rtn = isBigDataMethod.invoke(a1, "value1", 3);
// 此时就直接完成了方法的调用了

通过反射修改类属性

通过Class获取属性

Class中存在两个方法可以获取类属性,分别为
Field[] getFields() / Field getField(String name)
Field[] getDeclaredFields() / Field getDeclaredField(String name)

getFields(),只能获取public的属性,无法获取其他属性,Class源码和解释如下

/**
Returns an array containing Field objects reflecting all the accessible public fields of the class or interface represented by this Class object.
If this Class object represents a class or interface with no no accessible public fields, then this method returns an array of length 0.
If this Class object represents a class, then this method returns the public fields of the class and of all its superclasses.
If this Class object represents an interface, then this method returns the fields of the interface and of all its superinterfaces.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
Returns:
the array of Field objects representing the public fields
*/
// 通过Member.PUBLIC参数来控制只获取public属性
@CallerSensitive
    public Field[] getFields() throws SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return copyFields(privateGetPublicFields(null));
    }

getDeclaredFields(),则能获取public属性以及private属性,但是不能获取继承的属性

/**
Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this Class object. This includes public, protected, default (package) access, and private fields, but excludes inherited fields.
If this Class object represents a class or interface with no declared fields, then this method returns an array of length 0.
If this Class object represents an array type, a primitive type, or void, then this method returns an array of length 0.
The elements in the returned array are not sorted and are not in any particular order.
Returns:
the array of Field objects representing all the declared fields of this class
*/
@CallerSensitive
    public Field[] getDeclaredFields() throws SecurityException {
        checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
        return copyFields(privateGetDeclaredFields(false));
    }

则我们可以通过两种方式来获取属性

通过Class修改对象属性

既然都可以将属性获取出来了,此时也可以通过反射对对象设置属性值

// 首先通过反射来获取Class类
Class a = Class.forName("packeage.pojo.A");
// 通过Class实例化一个类
A a = (A) a.getConstructor().newInstance();
// 获取所有属性
Fields fields = a.getFields();
// 可以通过属性名称来获取Field对象
Field attrA = a.getField("属性名称");
// 直接调用Field.set(类对象Object, value)即可修改属性值
attrA.set(a, "value"); // 此时就是给a对象的attrA属性设置值了

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:42:26  更:2021-10-27 12:43:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:31:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码