java高级编程-使用反射强制给private字段赋值
转自:http://blog.csdn.net/yaerfeng/article/details/7103397
今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方法中做为参数。
实际操作时才发现,这个类中的字段属性是私有的,不能进行赋值!没有提供公有的方法。而这个类又是打包成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,01201101", "mobile,15810022404", "content,测试数据。");
- Smss sms = (Smss) object;
- System.out.println("短信内容:" + sms.getContent());
- System.out.println("手机号码:" + sms.getMobile());
- System.out.println("尾号:" + sms.getDestID());
- }
- }
控制台输出:
短信内容:测试数据。
手机号码:15810022404
尾号:01201101
fields.setAccessible(true);的使用可能大家都会,但我们要做的是,知其然,知其所以然。
看JDK的源码,无疑是学习和解决此方法的最佳途径。
over~~~
java高级编程-使用反射强制给private字段赋值的更多相关文章
- java使用反射强制给private字段赋值
今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方法中做为参数. 实际操作时才发现,这个类中的字段属性是私有的,不能进行赋值!没有提供公有的方法.而这个类又是打包成 ...
- Java高级语法之反射
Java高级语法之反射 什么是反射 java.lang包提供java语言程序设计的基础类,在lang包下存在一个子包:reflect,与反射相关的APIs均在此处: 官方对reflect包的介绍如下: ...
- java高级编程笔记(四)
java的Object类: 1.Object 类位于 java.lang 包中,编译时会自动导入:Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法. 2.Object ...
- Java高级特性之反射学习总结
老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用 ...
- Java高级特性之反射
老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用 ...
- 【java高级编程】JDK和CGLIB动态代理区别
转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...
- 【java高级编程】jdk自带事件模型编程接口
事件类 java.util.EventObject java.beans.PropertyChangeEvent 事件监听接口 java.util.EventListener java.beans.P ...
- JAVA高级编程数据源datasource
原文链接 数据源 通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: ...
- JAVA高级编程(数据源datasource)
数据源:通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: comm ...
随机推荐
- 如何理解redo和undo的作用
目录 如何理解redo和undo的作用 redo undo UNDO和REDO的区别 如何理解redo和undo的作用 redo 重做日志(redo)包含所有数据产生的历史改变记录,是oracle在线 ...
- 软件工程师应该关注的web攻击手段
1.SQL注入------常见的安全性问题. 解决方案:前端页面需要校验用户的输入数据(限制用户输入的类型.范围.格式.长度),不能只靠后端去校验用户数据.一来可以提高后端处理的效率,二来可以提高后端 ...
- bootstrap里的fileimput的小问题
fileinput 是bootstrap 里面一个非常好的插件 于是我很开心的开始的使用了 $("#file_upload").fileinput({ uploadUrl: &qu ...
- 【NOIP2016】愤怒的小鸟 搜索
题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0)(0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟,小 ...
- Codeforces Round #412 Div. 2 第一场翻水水
大半夜呆在机房做题,我只感觉智商严重下降,今天我脑子可能不太正常 A. Is it rated? time limit per test 2 seconds memory limit per test ...
- 【Luogu】P3343地震后的幻想乡(对积分概率进行DP)
题目链接 神难qwq.配合rqy的博客食用. 首先我们学到有一个概率函数$p(x)$表示某事件发生概率取值小于x的函数.这个函数有什么特点呢? 那就是$\int_{-∞}^{∞}p(x)dx=1$ 这 ...
- HDU——1799循环多少次(杨辉三角/动态规划/C(m,n)组合数)
循环多少次? Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- [LOJ#6002]「网络流 24 题」最小路径覆盖
[LOJ#6002]「网络流 24 题」最小路径覆盖 试题描述 给定有向图 G=(V,E).设 P 是 G 的一个简单路(顶点不相交)的集合.如果 V 中每个顶点恰好在 P 的一条路上,则称 P 是 ...
- BZOJ 4818 [Sdoi2017]序列计数 ——矩阵乘法
发现转移矩阵是一个循环矩阵. 然后循环矩阵乘以循环矩阵还是循环矩阵. 据说还有FFT并且更优的做法. 之后再看吧 #include <map> #include <cmath> ...
- class文件检查器
Class文件检查器保证装载的class文件内容有正确的内部结构,并且这些class文件互相间协调一致.Class文件检查器实现的安全目标之一就是程序的健壮性.如果某个有漏洞的编译器,或某个聪明的黑客 ...