Java反射 二三事
2015-10-10 10:03
399 查看
为什么需要反射
关于反射有很多场景可能会用到,这里用到是因为有一些私有方法必须要写单元测试。关于为什么会对私有方法进行单元测试,也许这并不是常见的需求。然而当外部环境变化很大(比如网站的url)时,保证你的函数正确有助于快速排错。
对私有方法反射的主要流程
1.首先获得方法A所在类的Class object,即通过Class.forName(ClassName)以及 object.newInstance()获得。注意这里的ClassName包含类所在的包名。
2.利用刚才得到的Class object调用getDeclaredMethod(String name, Class<?>... parameterTypes)方法。前一个参数是nonpublic方法A的名字,后面的参数是包含方法A的各个参数的类型的Class Object。这样就可以得到方法A的object,原文描述为:Returns a Method object that reflects the specified declared method of the class or interface
represented by this Class object。
Method A’= getDeclaredMethod(“A”,Class<?>... parameterTypesOf”A”) 也可以保留方法A原名,这里为了区分命名为A’。
3.设置方法A’的可见性A’.setAccessible(true);
4.调用A’方法,注意一定要invoke()====>A’.invoke(A所在类的Classobject, A的参数)。
对私有字段反射的主要流程
1.和私有方法的反射类似2.利用刚才得到的Class object调用getDeclaredField(String fieldName)获取字段对象fieldObj。
3.设置字段可见性fieldObj.setAccessible(true);
4.设置字段fieldObj.set(object, value)
获取字段的值fieldObj.get(object)
一个基本和典型的私有方法反射示例
(1)写个类
package xxx.yyy.zzz public class Simple { private void displayMessage(String strMsg) { System.out.println("message is:" + strMsg); } }
(2)反射调用 import java.lang.reflect.*; public class Test { public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class simpleClass = Class.forName("xxx.yyy.zzz.Simple"); Object simpelObject = simpleClass.newInstance(); Class[] args1 = new Class[1]; args1[0] = String.class; Method simpleMethod = simpleClass.getDeclaredMethod("displayMessage",arg1); simpleMethod.setAccessible(true); String[] argments = new String[1]; argments[0] = "Hello,world"; simpleMethod.invoke(simpelObject, argments); } }
复杂参数类型的反射示例
这里才是重点!通常invoke返回值是Object对象,通过对它强制类型转换可以得到复杂类型的返回值,比如数组,集合等等(当然前提是你强制转换的类型和你的函数定义一致)。
先放一个数组的例子,假设有如下的类:
package org.apache.nutch.parse.html; public class TestOnly { private String[] array= new String[4]; private String[] getStringArray(){ return array; } private void setStringArray(String[] values){ array=values; } }
它的array数据和对应的set/get方法都是私有的
package org.apache.nutch.parse.html; import org.junit.Test; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import static org.junit.Assert.*; public class TestOnlyTest { @Test public void testGetStringArray() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, MalformedURLException, NoSuchFieldException { Class testObj = Class.forName("org.apache.nutch.parse.html.TestOnly"); Object obj = testObj.newInstance(); /*test set method.*/ Method setArray = testObj.getDeclaredMethod("setStringArray", new Class[]{String[].class}); setArray.setAccessible(true); String[] name = {"hello", "world"}; setArray.invoke(obj, new Object[]{name}); /*test get method.*/ Method getArray = testObj.getDeclaredMethod("getStringArray"); getArray.setAccessible(true); String[] result = (String[])getArray.invoke(obj); assertEquals("hello",result[0]); assertEquals("world",result[1]); /*test private field visit.*/ Field array =testObj.getDeclaredField("array"); array.setAccessible(true); array.set(obj, new String[]{"come","here","baby"}); result = (String[])array.get(obj); assertEquals("come",result[0]); assertEquals("here",result[1]); assertEquals("baby",result[2]); } }当然不用单元测试,也可以用通过打印语句来验证结果集的正确性。
再放一个工作中实际用到的小例子。
自定义nutch的解析类 实现Parser接口定义的抽象方法如下:
@Override public ArrayList<Outlink> filterOutlinks(ArrayList<Outlink> list) { ArrayList<Outlink> filterList = new ArrayList<Outlink>(); Outlink filterLink = null; for (Outlink outlink : list) { if (isCrawlOutLineUrl(outlink.getToUrl())) { try { filterLink = new Outlink(outlink.getToUrl(), "ydss"); } catch (MalformedURLException e) { dMsg.warn("MalformedURLException:", e); continue; } if (!filterList.contains(filterLink)) { filterList.add(filterLink); } } } return filterList; }
其中isCrawlOutLineUrl是一个判断是否为合法出链的私有方法,具体逻辑忽略,此外用到了一个私有字段url。
对应的单元测试如下:
// @Test public void testIsCrawlOutLineUrl() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchFieldException{ String outLinkUrl = "http://bbs.ydss.cn/thread-199593-1-1.html"; Class ypObj = Class.forName("org.apache.nutch.parse.html.YdssParser"); Object yp = ypObj.newInstance(); Method isCrawlOutLineUrl = ypObj.getDeclaredMethod("isCrawlOutLineUrl", new Class[]{String.class}); isCrawlOutLineUrl.setAccessible(true); Field url = ypObj.getDeclaredField("url"); url.setAccessible(true); url.set(yp, "http://bbs.ydss.cn/forum.php?mod=viewthread&tid=505896&extra=page%3D1%26filter%3Dauthor%26orderby%3Ddateline"); assertFalse((Boolean) isCrawlOutLineUrl.invoke(yp, outLinkUrl)); outLinkUrl = "http://bbs.ydss.cn/thread-505896-1-1.html"; assertFalse((Boolean) isCrawlOutLineUrl.invoke(yp, outLinkUrl)); }
以上是最近写私有方法和字段的单元测试所获的一些心得,分享,备忘。
相关文章推荐
- JavaSE8-The New Date and Time API(2)
- struts配置之namespace
- Java学习总结--日期
- Java 年轻代GC
- java.util.ConcurrentModificationException异常。
- java中链表的实现类LinkedList
- Java servlet中cookie中文乱码解决
- Eclipse启动时DDMS files not found: D:\Eclipse\adt-bundle-windows-x86_64-20131030\sdk\tool
- Gson 对浮点数的格式化
- 【Java学习笔记】之一
- 解惑rJava R与Java的高速通道
- Java基础知识强化之集合框架笔记64:Map集合之ArrayList嵌套HashMap
- 循环双链表的插入和删除的一些基本操作java版
- Java并发编程:阻塞队列
- java int 乘法溢出问题
- Java基础知识强化之集合框架笔记63:Map集合之HashMap嵌套ArrayList
- springmvc简介
- eclipse使用hadoop来统计单词的个数
- Java基础知识强化之集合框架笔记62:Map集合之HashMap嵌套HashMap
- eclipse调试以及各个键的作用