知识大全 Java反射访问私有变量和私有方法

Posted 变量

篇首语:成功的人是跟别人学习经验,失败的人只跟自己学习经验。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java反射访问私有变量和私有方法相关的知识,希望对你有一定的参考价值。

Java反射访问私有变量和私有方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  引言

  对于软件开发人员来说 单元测试是一项必不可少的工作 它既可以验证程序的有效性 又可以在程序出现 BUG 的时候 帮助开发人员快速的定位问题所在 但是 在写单元测试的过程中 开发人员经常要访问类的一些非公有的成员变量或方法 这给测试工作带来了很大的困扰 本文总结了访问类的非公有成员变量或方法的四种途径 以方便测试人员在需要访问类非公有成员变量或方法时进行选择

  尽管有很多经验丰富的程序员认为不应该提倡访问类的私有成员变量或方法 因为这样做违反了 Java 语言封装性的基本规则 然而 在实际测试中被测试的对象千奇百怪 为了有效快速的进行单元测试 有时我们不得不违反一些这样或那样的规则 本文只讨论如何访问类的非公有成员变量或方法 至于是否应该在开发测试中这样做 则留给读者自己根据实际情况去判断和选择

  方法一 修改访问权限修饰符

  先介绍最简单也是最直接的方法 就是利用 Java 语言自身的特性 达到访问非公有成员的目的 说白了就是直接将 private 和 protected 关键字改为 public 或者直接删除 我们建议直接删除 因为在 Java 语言定义中 缺省访问修饰符是包可见的 这样做之后 我们可以另建一个源码目录 —— test 目录(多数 IDE 支持这么做 如 Eclipse 和 JBuilder) 然后将测试类放到 test 目录相同包下 从而达到访问待测类的成员变量和方法的目的 此时 在其它包的代码依然不能访问这些变量或方法 在一定程度上保障了程序的封装性

  下面的代码示例展示了这一方法

  清单 原始待测类 A 代码

  public class A     private String name = null;    private void calculate()    

  清单 针对单元测试修改后的待测类 A 的代码

  public class A     String name = null;    private void calculate()    

  这种方法虽然看起来简单粗暴 但经验告诉我们这个方法在测试过程中是非常有效的 当然 由于改变了源代码 虽然只是包可见 也已经破坏了对象的封装性 对于多数对代码安全性要求严格的系统此方法并不可取

  方法二 利用安全管理器

  安全性管理器与反射机制相结合 也可以达到我们的目的 Java 运行时依靠一种安全性管理器来检验调用代码对某一特定的访问而言是否有足够的权限 具体来说 安全性管理器是 java lang SecurityManager 类或扩展自该类的一个类 且它在运行时检查某些应用程序操作的权限 换句话说 所有的对象访问在执行自身逻辑之前都必须委派给安全管理器 当访问受到安全性管理器的控制 应用程序就只能执行那些由相关安全策略特别准许的操作 因此安全管理器一旦启动可以为代码提供足够的保护 默认情况下 安全性管理器是没有被设置的 除非代码明确地安装一个默认的或定制的安全管理器 否则运行时的访问控制检查并不起作用 我们可以通过这一点在运行时避开 Java 的访问控制检查 达到我们访问非公有成员变量或方法的目的 为能访问我们需要的非公有成员 我们还需要使用 Java 反射技术 Java 反射是一种强大的工具 它使我们可以在运行时装配代码 而无需在对象之间进行源代码链接 从而使代码更具灵活性 在编译时 Java 编译程序保证了私有成员的私有特性 从而一个类的私有方法和私有成员变量不能被其他类静态引用 然而 通过 Java 反射机制使得我们可以在运行时查询以及访问变量和方法 由于反射是动态的 因此编译时的检查就不再起作用了

  下面的代码演示了如何利用安全性管理器与反射机制访问私有变量

  清单 利用反射机制访问类的成员变量

  //获得指定变量的值

  public static Object getValue(Object instance String fieldName)

  throws   IllegalAccessException NoSuchFieldException

  Field field = getField(instance getClass() fieldName);

  // 参数值为true 禁用访问控制检查

  field setAccessible(true);

  return field get(instance);

  

  //该方法实现根据变量名获得该变量的值

  public static Field getField(Class thisClass String fieldName)

  throws NoSuchFieldException

  if (thisClass == null)

  throw new NoSuchFieldException( Error field ! );

  

  

  其中 getField(instance getClass() fieldName) 通过反射机制获得对象属性 如果存在安全管理器 方法首先使用 this 和 Member DECLARED 作为参数调用安全管理器的 checkMemberAccess 方法 这里的 this 是 this 类或者成员被确定的父类 如果该类在包中 那么方法还使用包名作为参数调用安全管理器的 checkPackageAccess 方法 每一次调用都可能导致 SecurityException 当访问被拒绝时 这两种调用方式都会产生 securityexception 异常

  setAccessible(true) 方法通过指定参数值为 true 来禁用访问控制检查 从而使得该变量可以被其他类调用 我们可以在我们所写的类中 扩展一个普通的基本类 java lang reflect AccessibleObject 类 这个类定义了一种 setAccessible 方法 使我们能够启动或关闭对这些类中其中一个类的实例的接入检测 这种方法的问题在于如果使用了安全性管理器 它将检测正在关闭接入检测的代码是否允许这样做 如果未经允许 安全性管理器抛出一个例外

  除访问私有变量 我们也可以通过这个方法访问私有方法

  清单 利用反射机制访问类的成员方法

  public static Method getMethod(Object instance String methodName Class[] classTypes)

  throws   NoSuchMethodException

  Method accessMethod = getMethod(instance getClass() methodName classTypes);

  //参数值为true 禁用访问控制检查

  accessMethod setAccessible(true);

  return accessMethod;

  

  private static Method getMethod(Class thisClass String methodName Class[] classTypes)

  throws NoSuchMethodException

  if (thisClass == null)

  throw new NoSuchMethodException( Error method ! );

   try

  return thisClass getDeclaredMethod(methodName classTypes);

   catch (NoSuchMethodException e)

  return getMethod(thisClass getSuperclass() methodName classTypes);

  

  

  获得私有方法的原理与获得私有变量的方法相同 当我们得到了函数后 需要对它进行调用 这时我们需要通过 invoke() 方法来执行对该函数的调用 代码示例如下

  //调用含单个参数的方法

  public static Object invokeMethod(Object instance String methodName Object arg)

  throws NoSuchMethodException

  IllegalAccessException InvocationTargetException

  Object[] args = new Object[ ];

  args[ ] = arg;

  return invokeMethod(instance methodName args);

  

  //调用含多个参数的方法

  public static Object invokeMethod(Object instance String methodName Object[] args)

  throws NoSuchMethodException

  IllegalAccessException InvocationTargetException

  Class[] classTypes = null;

  if (args != null)

  classTypes = new Class[args length];

  for (int i = ; i < args length; i++)

  if (args[i] != null)

  classTypes[i] = args[i] getClass();

  

  

  

  return getMethod(instance methodName classTypes) invoke(instance args);

  

  利用安全管理器及反射 可以在不修改源码的基础上访问私有成员 为测试带来了极大的方便 尤其是在编译期间 该方法可以顺利地通过编译 但同时该方法也有一些缺点 第一个是性能问题 用于字段和方法接入时反射要远慢于直接代码 第二个是权限问题 有些涉及 Java 安全的程序代码并没有修改安全管理器的权限 此时本方法失效

  另一种方法

  package test;

  import java lang reflect Field;

  import model Dept;

  public class TypeTest

  public static void main(String args[])

  

  Dept d=new Dept();

  d setDeptNo( );

  d setDName( v );

  d setLoc( mopish );

  delete(d Dept class);

  

  public static void delete(Object obj Class<?> clazz)

  

  try

  

  System out println( ? +(obj instanceof Dept));

  System out println(clazz getName());

  System out println(clazz getDeclaredFields() length);

  for(Field f: clazz getDeclaredFields())

  

  f setAccessible(true);

  System out println(f getName());

  System out println( +f get(obj));

  

  catch(Exception e)

  

  e printStackTrace();

  

  

  

  package model;

  public class Dept

  private long deptNo;

  private String DName;

  private String Loc;

  public long getDeptNo()

  return deptNo;

  

  public void setDeptNo(long deptNo)

  this deptNo = deptNo;

  

  public String getDName()

  return DName;

  

  public void setDName(String dName)

  DName = dName;

  

  public String getLoc()

  return Loc;

  

  public void setLoc(String loc)

  Loc = loc;

  

cha138/Article/program/Java/hx/201311/26190

相关参考

知识大全 java的volatile与多线程

  Java语言规范中指出为了获得最佳速度允许线程保存共享成员变量的私有拷贝而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比  Volatile修饰的成员变量在每次被线程访问时都强迫从

知识大全 JavaScript 模拟类机制及私有变量的方法及思路

JavaScript模拟类机制及私有变量的方法及思路  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 c#中private私有和public公有的区别是什么

c#中private私有和public公有的区别是什么private、protect、public、访问范围依次增大。private只限在本类中使用。protect允许它的子类访问。public修饰符

知识大全 构造函数和析构函数

  类构造函数  本节将讨论三种类构造函数  类构造函数的类型  注释  实例  用于创建并初始化类的实例  私有  在类之外不可访问的特殊类型实例构造函数无法用私有构造函数来实例化类  静态  在创

知识大全 Java中对线程间的变量访问也需要同步控制

Java中对线程间的变量访问也需要同步控制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一个简

下列关于私有财产的表述,不符合我国现行宪法规定的是

下列关于私有财产的表述,不符合我国现行宪法规定的是_____。A、公民的合法的私有财产不受侵犯B、任何人不得剥夺公民的私有财产C、国家依据法律规定保护公民的私有财产权和继承权D、国家为了公共利益的需要

知识大全 私有房产证和国有的区别是什么

私有房产证和国有的区别是什么?详细一点谢谢。国家土地分国家所有和集体所有一般来说修建的商品房是先把土地性质从集体转为国有取得大的国土证后才可以上市交易那么修建的房子就是具有法律意义上的产权证可以上市交

《宪法》规定公民的合法的私有财产不受侵犯。那么以下哪项属于公民的合法私有财产

《宪法》规定公民的合法的私有财产不受侵犯。那么以下哪项属于公民的合法私有财产?A、继承房屋B、坟地C、下属行贿的红包D、矿山答案:A解析:根据《宪法》第9条的规定,矿藏、水流、森林、山岭、草原、荒地、

私有股的形式

私有股的形式私有股是公民个人以合法财产投资形成股份的一种形式。在中国,按股权所有者分类,个人以合法财产投资形成的股份分为两类:一类是股份制企业的职工认购的本企业的股份,称“职工股”或“职工个人股”,它

商鞅变法主要内容是废除井田制,实行土地私有制,统一文字和度量衡

商鞅变法主要内容是废除井田制,实行土地私有制,统一文字和度量衡。_____答案:错误解析:商鞅变法的主要内容是废井田、重农桑、奖军功、实行统一度量和建立郡县等。统一全国文字和度量衡的是秦始皇。故本题判