转自:http://blog.csdn.net/yaerfeng/article/details/7103397

今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方法中做为参数。

实际操作时才发现,这个类中的字段属性是私有的,不能进行赋值!没有提供公有的方法。而这个类又是打包成jar给我的,我还不能更改它的代码,以至于想手动给它写个set方法都是问题。后来想到用反射可以解决这个问题,于是试了一下,果然!

反射看来根本不区分是否是private的,调用本身的私有方法是可以的,但是调用父类的私有方法则不行,纠其原因很有可能是因为getDeclaredMethod方法和getMethod方法并不会查找父类的私有方法,自己写递归可以解决,不过利用反射来做的话性能不会太好。

我们来看下面这个代码。

  1. Field[] fields = obj.getDeclaredFields();
  2. for (int i = 0; i < fields.length; i++) {
  3. fields[i].setAccessible(true);
  4. for (int j = 0; j < args.length; j++) {
  5. String str = args[j];
  6. String strs[] = str.split(",");
  7. if (strs[0].equals(fields[i].getName())) {
  8. fields[i].set(object, strs[1]);
  9. break;
  10. }
  11. }
  12. }
  1. fields[i].setAccessible(true);

这句话是关键。看它的表面英文意思是设置可进入可访问为:true。编程意思大家猜想也应该知道了。

通过查看JDK的源码:

  1. public void setAccessible(boolean flag) throws SecurityException {
  2. SecurityManager sm = System.getSecurityManager();
  3. if (sm != null) sm.checkPermission(ACCESS_PERMISSION);
  4. setAccessible0(this, flag);
  5. }

我们可以看到它是通过SecurityManager来管理权限的,我们可以启用java.security.manager来判断程序是否具有调用setAccessible()的权限。默认情况下,内核API和扩展目录的代码具有该权限,而类路径或通过URLClassLoader加载的应用程序不拥有此权限。例如:当我们以这种方式来执行上述程序时将会抛出异常

  1. java.security.AccessControlException:   access   denied

一般情况下,我们并不能对类的私有字段进行操作,但有的时候我们又必须有能力去处理这些字段,这时候,我们就需要调用AccessibleObject上的setAccessible()方法来允许这种访问,而由于反射类中的Field,Method和Constructor继承自AccessibleObject,因此,通过在这些类上调用setAccessible()方法,我们可以实现对这些字段的操作。

我们来看看这个ACCESS_PERMISSION里面究竟怎么处理的:

  1. static final private java.security.Permission ACCESS_PERMISSION =
  2. 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原有的权限体系。所以不到万不得已,还是少用,反射的效率毕竟不是那么高滴。

好,知道了这个我们再来写一个通用的万能方法,只是传递相应的类,字段名称和值,我们在方法内部将其反射并进行实例化。然后进行相应字段的赋值。由于我只用到了字段。你可以加上其它的东东。嗯。这个好玩。

  1. package unit.sms;
  2. public class Smss {
  3. private String destID;
  4. private String content;
  5. private String mobile;
  6. public String getDestID() {
  7. return destID;
  8. }
  9. public String getContent() {
  10. return content;
  11. }
  12. public String getMobile() {
  13. return mobile;
  14. }
  15. }
  1. package com.sinoglobal.utils;
  2. import java.lang.reflect.Field;
  3. import com.jasson.mas.api.smsapi.Sms;
  4. /**
  5. * 反射的通用工具类
  6. *
  7. * @author lz
  8. *
  9. */
  10. public class ReflectionUtils {
  11. /**
  12. * 用于对类的字段赋值,无视private,project修饰符,无视set/get方法
  13. * @param c 要反射的类
  14. * @param args 类的字段名和值 每个字段名和值用英文逗号隔开
  15. * @return
  16. */
  17. @SuppressWarnings("unchecked")
  18. public static Object getInstance(Class c, String... args) {
  19. try {
  20. Object object = Class.forName(c.getName()).newInstance();
  21. Class<?> obj = object.getClass();
  22. Field[] fields = obj.getDeclaredFields();
  23. for (int i = 0; i < fields.length; i++) {
  24. fields[i].setAccessible(true);
  25. for (int j = 0; j < args.length; j++) {
  26. String str = args[j];
  27. String strs[] = str.split(",");
  28. if (strs[0].equals(fields[i].getName())) {
  29. fields[i].set(object, strs[1]);
  30. break;
  31. }
  32. }
  33. }
  34. return object;
  35. } catch (IllegalAccessException e) {
  36. e.printStackTrace();
  37. } catch (ClassNotFoundException e) {
  38. e.printStackTrace();
  39. } catch (InstantiationException e) {
  40. e.printStackTrace();
  41. }
  42. return null;
  43. }
  44. public static void main(String[] args) {
  45. Object object = getInstance(Smss.class, "destID,01201101", "mobile,15810022404", "content,测试数据。");
  46. Smss sms = (Smss) object;
  47. System.out.println("短信内容:" + sms.getContent());
  48. System.out.println("手机号码:" + sms.getMobile());
  49. System.out.println("尾号:" + sms.getDestID());
  50. }
  51. }

控制台输出:

短信内容:测试数据。
手机号码:15810022404
尾号:01201101

fields.setAccessible(true);的使用可能大家都会,但我们要做的是,知其然,知其所以然。

看JDK的源码,无疑是学习和解决此方法的最佳途径。

over~~~

java高级编程-使用反射强制给private字段赋值的更多相关文章

  1. java使用反射强制给private字段赋值

    今天项目中遇到了一个问题,要调用一个类,并获取这个类的属性进行赋值然后将这个类传递到方法中做为参数. 实际操作时才发现,这个类中的字段属性是私有的,不能进行赋值!没有提供公有的方法.而这个类又是打包成 ...

  2. Java高级语法之反射

    Java高级语法之反射 什么是反射 java.lang包提供java语言程序设计的基础类,在lang包下存在一个子包:reflect,与反射相关的APIs均在此处: 官方对reflect包的介绍如下: ...

  3. java高级编程笔记(四)

    java的Object类: 1.Object 类位于 java.lang 包中,编译时会自动导入:Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法. 2.Object ...

  4. Java高级特性之反射学习总结

    老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用 ...

  5. Java高级特性之反射

    老规矩我们还是先提出几个问题,一门技术必然要能解决一定的问题,才有去学习掌握它的价值 一. 什么是反射? 二.反射能做什么? 一. 什么是反射? 用在Java身上指的是我们可以于运行时加载.探知.使用 ...

  6. 【java高级编程】JDK和CGLIB动态代理区别

    转载:https://blog.csdn.net/yhl_jxy/article/details/80635012 前言 JDK动态代理实现原理(jdk8):https://blog.csdn.net ...

  7. 【java高级编程】jdk自带事件模型编程接口

    事件类 java.util.EventObject java.beans.PropertyChangeEvent 事件监听接口 java.util.EventListener java.beans.P ...

  8. JAVA高级编程数据源datasource

    原文链接 数据源 通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: ...

  9. JAVA高级编程(数据源datasource)

    数据源:通过jdbc连接数据库,多建立几条连接放在数据源里面.可以设置数据源的最大连接数,同时活跃的连接数,最少空闲的连接数,能够同时接收处理的连接数等等. dbcp数据源 需要的jar包: comm ...

随机推荐

  1. Post页面爬取失败__编码问题

    python3爬取Post页面时, 报以下错误 "POST data should be bytes or an iterable of bytes. It cannot be of typ ...

  2. Java学习——面对对象的思想入门

          本文是看过<head first Java>之后的一点感悟,写点东西帮忙以后回忆,Java目前在我的工作中用到还不多,而我又对面对对象的编程非常的感兴趣.曾经在MFC平台上写过 ...

  3. Jenkins自动化搭建测试环境(二)

    Fork项目 找到项目 单击Fork 这时,会发送一个邮件到你的git邮箱中,点击链接即可完成fork 这样,这个工程就已经fork到自己的git上了 然后就可以下载这个工程到本机了 这里我们需要使用 ...

  4. Leetcode 481.神奇字符串

    神奇字符串 神奇的字符串 S 只包含 '1' 和 '2',并遵守以下规则: 字符串 S 是神奇的,因为串联字符 '1' 和 '2' 的连续出现次数会生成字符串 S 本身. 字符串 S 的前几个元素如下 ...

  5. 聊聊、Java Keytool P12 转 JKS

    最近公司合作机构需要更改服务证书,总共给了 3 个文件过来.openapi-cert.p12.openapi-cert.key.openapi-cert.crt. openapi-cert.crt - ...

  6. [git 学习篇]远程创库

    实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交. 完全 ...

  7. iOS学习笔记47-Swift(七)泛型

    一.Swift泛型介绍 泛型是为Swift编程灵活性的一种语法,在函数.枚举.结构体.类中都得到充分的应用,它的引入可以起到占位符的作用,当类型暂时不确定的,只有等到调用函数时才能确定具体类型的时候可 ...

  8. BZOJ1195 [HNOI2006]最短母串 【状压dp】

    题目 给定n个字符串(S1,S2,„,Sn),要求找到一个最短的字符串T,使得这n个字符串(S1,S2,„,Sn)都是T的子串. 输入格式 第一行是一个正整数n(n<=12),表示给定的字符串的 ...

  9. BZOJ3505 & 洛谷P3166 [Cqoi2014]数三角形 【数学、数论】

    题目 给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个.下图为4x4的网格上的一个三角形. 注意三角形的三点不能共线. 输入格式 输入一行,包含两个空格分隔的正整数m和n. 输出格式 输出 ...

  10. 面试题之redis单线程为什么性能很高

    原因是,使用了多路复用技术. 什么是多路复用技术:多个客户端使用一个信道,并且通过一个信道进行传输