java使用反射强制给private字段赋值
今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方法中做为参数。
实际操作时才发现,这个类中的字段属性是私有的,不能进行赋值!没有提供公有的方法。而这个类又是打包成jar给我的,我还不能更改它的代码,以至于想手动给它写个set方法都是问题。后来想到用反射可以解决这个问题,于是试了一下,果然!
反射看来根本不区分是否是private的,调用本身的私有方法是可以的,但是调用父类的私有方法则不行,纠其原因很有可能是因为getDeclaredMethod方法和getMethod方法并不会查找父类的私有方法,自己写递归可以解决,不过利用反射来做的话性能不会太好。
我们来看下面这个代码。
- Field[] fields = obj.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- fields[i].setAccessible(true);
- for (int j = 0; j < args.length; j++) {
- String str = args[j];
- String strs[] = str.split(",");
- if (strs[0].equals(fields[i].getName())) {
- fields[i].set(object, strs[1]);
- break;
- }
- }
- }
- fields[i].setAccessible(true);
这句话是关键。看它的表面英文意思是设置可进入可访问为:true。编程意思大家猜想也应该知道了。
通过查看JDK的源码:
- public void setAccessible(boolean flag) throws SecurityException {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
- setAccessible0(this, flag);
- }
我们可以看到它是通过SecurityManager来管理权限的,我们可以启用java.security.manager来判断程序是否具有调用setAccessible()的权限。默认情况下,内核API和扩展目录的代码具有该权限,而类路径或通过URLClassLoader加载的应用程序不拥有此权限。例如:当我们以这种方式来执行上述程序时将会抛出异常
- java.security.AccessControlException: access denied
一般情况下,我们并不能对类的私有字段进行操作,但有的时候我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承自AccessibleObject,因此,通过在这些类上调用setAccessible()方法,我们可以实现对这些字段的操作。
我们来看看这个ACCESS_PERMISSION里面究竟怎么处理的:
- static final private java.security.Permission ACCESS_PERMISSION =
- new ReflectPermission("suppressAccessChecks");
查找JDK帮助文档可以看到详细解释:
public final class ReflectPermissionextends BasicPermission
反射操作的 Permission 类。ReflectPermission 是一种指定权限,没有动作。当前定义的唯一名称是suppressAccessChecks,它允许取消由反射对象在其使用点上执行的标准 Java 语言访问检查 - 对于 public、default(包)访问、protected、private 成员。
下表提供了允许权限的简要说明,并讨论了授予代码权限的风险。
权限目标名称 | 权限允许的内容 | 允许此权限的风险 |
---|---|---|
suppressAccessChecks |
能够访问类中的字段和调用方法。注意,这不仅包括 public、而且还包括 protected 和 private 字段和方法。 |
存在的风险是,通常不可用的信息(也许是保密信息)和方法可能会接受恶意代码访问。 |
这里就一点了然了。fields.setAccessible(true);的实际作用就是使权限可以访问public,protected,private的字段!
是不是很爽呢。当然这种方法破坏了JAVA原有的权限体系。所以不到万不得已,还是少用,反射的效率毕竟不是那么高滴。
好,知道了这个我们再来写一个通用的万能方法,只是传递相应的类,字段名称和值,我们在方法内部将其反射并进行实例化。然后进行相应字段的赋值。由于我只用到了字段。你可以加上其它的东东。嗯。这个好玩。
- package unit.sms;
- public class Smss {
- private String destID;
- private String content;
- private String mobile;
- public String getDestID() {
- return destID;
- }
- public String getContent() {
- return content;
- }
- public String getMobile() {
- return mobile;
- }
- }
- package com.sinoglobal.utils;
- import java.lang.reflect.Field;
- import com.jasson.mas.api.smsapi.Sms;
- /**
- * 反射的通用工具类
- *
- * @author lz
- *
- */
- public class ReflectionUtils {
- /**
- * 用于对类的字段赋值,无视private,project修饰符,无视set/get方法
- * @param c 要反射的类
- * @param args 类的字段名和值 每个字段名和值用英文逗号隔开
- * @return
- */
- @SuppressWarnings("unchecked")
- public static Object getInstance(Class c, String... args) {
- try {
- Object object = Class.forName(c.getName()).newInstance();
- Class<?> obj = object.getClass();
- Field[] fields = obj.getDeclaredFields();
- for (int i = 0; i < fields.length; i++) {
- fields[i].setAccessible(true);
- for (int j = 0; j < args.length; j++) {
- String str = args[j];
- String strs[] = str.split(",");
- if (strs[0].equals(fields[i].getName())) {
- fields[i].set(object, strs[1]);
- break;
- }
- }
- }
- return object;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- }
- return null;
- }
- public static void main(String[] args) {
- Object object = getInstance(Smss.class, "destID,08340001", "mobile,13408340000", "content,ReYo测试数据。");
- Smss sms = (Smss) object;
- System.out.println("短信内容:" + sms.getContent());
- System.out.println("手机号码:" + sms.getMobile());
- System.out.println("尾号:" + sms.getDestID());
- }
- }
控制台输出:
短信内容:ReYo测试数据。
手机号码:13408340000
尾号:08340001
fields.setAccessible(true);的使用可能大家都会,但我们要做的是,知其然,知其所以然。
看JDK的源码,无疑是学习和解决此方法的最佳途径。
java使用反射强制给private字段赋值的更多相关文章
- java高级编程-使用反射强制给private字段赋值
转自:http://blog.csdn.net/yaerfeng/article/details/7103397 今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方 ...
- Java 使用反射拷贝对象一般字段值
在<Java解惑>上面看到第八十三例--诵读困难者,要求使用非反射实现单例对象的拷贝.查阅了部分资料,先实现通过反射拷贝对象. 1. 编写需要被拷贝的对象Person package co ...
- 通过Field (反射)给私有字段赋值
public class Person { public String name; public char sex; private int age; public String getName() ...
- java 利用反射机制,获取实体所有属性和方法,并对属性赋值
一个普通的实体Person: private int id; private String name; private Date createdTime;...//其它字段// get set方法 . ...
- Java反射 - 简单的给Bean赋值和取值
由于项目的实际需要,所以利用java反射原理写了一个简单给bean赋值和取值通用的类,在此记录下方便自己日后用到,也为需要的兄弟提供个参考例子. 工具类BeanRefUtil: package c ...
- Java基础-反射(reflect)技术详解
Java基础-反射(reflect)技术详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.类加载器 1>.JVM 类加载机制 如下图所示,JVM类加载机制分为五个部分 ...
- 如何解决CRUD操作中与业务无关的字段赋值
提高效率一直是个永恒的话题,编程中有一项也是可以提到效率的,那就是专注做一件事情,让其它没有强紧密联系的与之分开.这里分享下我们做CRUD时遇到的常见数据处理场景: 数据库表字段全部设计为非空,即使这 ...
- java之反射的基本介绍
什么是反射 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法:这种动态获取的以及动态调用对象的方法的功能称为Java的反射 ...
- 面试题思考:什么是 Java 的反射机制
一.反射机制概述 Java 反射机制是在运行状态中,对于任意一个类,都能够获得这个类的所有属性和方法,对于任意一个对象都能够调用它的任意一个属性和方法.这种在运行时动态的获取信息以及动态调用对象的方法 ...
随机推荐
- vue组件库(一):前期准备工作
前言 将近期项目内自行开发一个vue组件,做个总结,记录下自己的思维过程~~~ 正文 接到这个任务后,还是要做些准备工作的. 主要内容如下: 1.优化下所在团队前端开发流程 服务器搭建gitlab,采 ...
- KnockoutJs学习笔记(七)
if binding与visible binding类似.不同之处在于,包含visible binding的元素会在DOM中一直保存,并且该元素相应的data-bind属性会一直保持,visible ...
- 195 Tenth Line
Given a text file file.txt, print just the 10th line of the file. Example: Assume that file.txt has ...
- 【LOJ】#2278. 「HAOI2017」字符串
题解 好神仙的题啊 感觉转二维平面能想到,算重复情况的方法真想不到啊 通过扒stdcall代码获得的题解QAQQQQ 我们先把\(p_i\)正串反串建出一个AC自动机来 然后我们把s串放在上面跑匹配, ...
- Hashmap jdk7 死循环
如果理解的有问题,欢迎大家指正. https://www.cnblogs.com/webglcn/p/10587708.html jdk7的hashmap 由数组和链表组成,存在几个问题: 当key的 ...
- 用scrapy爬取京东的数据
本文目的是使用scrapy爬取京东上所有的手机数据,并将数据保存到MongoDB中. 一.项目介绍 主要目标 1.使用scrapy爬取京东上所有的手机数据 2.将爬取的数据存储到MongoDB 环境 ...
- SpringBoot详细研究-03系统集成
据说杰克船长被黑客盗片了,看来信息安全依然任重而道远,本文以此为引子,来介绍下spring boot对于系统集成方面的支持. Spring Security提供一套安全框架,通过IOC和AOP来实现安 ...
- Java文件类
在Java语言中,无论是目录还是文件,都抽象成java.io.File类 直接上示例吧 java,io,File的常用操作 删除.创建 因为我的e盘里面是没有这个文件的,所以不存在I哦 创建文件: 获 ...
- [转]C++中vector使用详细说明
一.向量的介绍 向量 vector 是一种对象实体, 能够容纳许多其他类型相同的元素, 因此又被称为容器. 与string相同, vector 同属于STL(Standard Template ...
- BZOJ 4198: [Noi2015]荷马史诗 哈夫曼树 k叉哈夫曼树
https://www.lydsy.com/JudgeOnline/problem.php?id=4198 https://blog.csdn.net/chn_jz/article/details/7 ...