Java反射机制及应用(一)
类型:原创 | 日期:2012-09-04 13:29 | 标签:#java
Java,本身是一门非常优秀的面向对象语言,严格的面向对象语法,跨平台,学习简单…使用相当广泛,它的优秀是无可厚非的,但它也有一些争议,比如class文件的半编译方式会降底系统性能,还有单继承的限制有时候让人不爽(可以理解,但这点我支持java的方式),还有最重要的就是Java导致很多开发人员只会编代码,而对很多计算机科学应该知道的知识不了解.因为Java太上层了.但如果一个java出生的程序员又对计算机科学有广泛的爱好,那java可以带来很多面向对象编程,架构等等的思路指导.而且现在很多的脚本语言都是趋近于java的语法,如果你能理解Java的精髓,那么Javascript,Flash的ActionScript,甚至PHP对你来说都很简单(我就是这样).当然相关方面应用的知识是一定要知道的~程序语言只是工具而已!!
Java的应用很广泛,桌面程序,服务器应用,手持设备,其它设备基本上都支持由java来驱动.我们也可以扩展Java虚拟机(JNI,或源代码级修改)(哈哈,这是我最喜欢做的事了),使自己的Java虚拟机可以提供自己的包给上层开发人员调用,这些包可能直接操作设备,也可能是像支付功能一样的那些”只能让少数重要的人员维护”的功能.
吹了这么多废话,说说Java的反射机制吧,通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们.
给大家一些反射机制应用的举例:
- 分析类文件,如果你要做Java的IDE,又不想分析源代码,或许用反射机制,可以取得任意一个类的所有基本信息.eclipse可能就是这样实现的.(我说可能,是因为eclipse要分析C或其它语言的时候,还是得分析源代码)
- 脚本引擎,怎么样让一串字符串命令执行起来?这就要靠反射机制去动态创建类,动态执行里面的函数,所以,它甚至可以拿来远程注入代码,我怕教坏了你们这群孩子,就不明确地说它了.
- 访问一些不能访问的变量或属性,做破解也挺有用.但自己开发个人觉得这样的功能完全不要去用它,不然你的代码就是火星文,而你,也就成了火星人.所以本文里我不会过多讲它怎么越界访问变量.
上面这些都是我能想到的.当然实际还可以做很多很多的事.
Class类
java反射的核心类包括Class,Method,Field等,Class<T>这个类,用过C++的STL的人都熟悉,它代表一个类型.Java里通过它,可以取得这个类的所有信息,包括类的成员,函数,构造函数等信息.我们可以用Class.forName方法通过字符串或得这个类型,如:Class<String>可以通过 Class.forName(“java.lang.String”)取得.也可以通过一个对象,去取得它的Class,如
Object a=new Object();
Class c=a.getClass();//取得一个对象所关联的Class.
有些基本类型,比如int,它不属于什么类(严格地说,是属于java.lang.Number类),所以一般都用int.class直接取得.取得这一个Class对象了,就可以用它的newInstance 创建这个类的实例. 如下面的语句:
Object str=Class.forName(“java.lang.String”).newInstance();
相当于
Object str=new String();
可能很多人看不出上面使用反射机制生成对象有什么优势,下面的写法多简单啊.但请注意,下面的语句是在编代码的时候写死的.而上面语句,如果java.lang.String这个参数是其它字符串,那创建的就是其它类的实例.这个字符串可以来自于磁盘,来自于网络,或来自于用户输入.所以,它就是活的.
当然,上面的问题在于,你只能使用无参数的构造函数,这样肯定不行,所以,需要用Class去取得Constructor对象,再调用它的newInstance函数,就可以通过任意构造函数创建对象了.取得Constructor对象的方法和后面取得Method的方法差不多.
有一点一定不要迷糊:
1.类和对象的概念
2.Class类,和Class类的对象的概念.
概念2里,Class是一个类,Class类的对象是一个对象.它是完全附合概念1的,只不过Class类的对象是封装一个类的信息罢了!这点千万别迷糊!!!
Field类
它就是类成员变量的对象. Field有一系列的set函数,可以为指定对象的Field设定值.一个Field可以通过Class的getDeclaredField获得.然后使用它的setXXX函数去为某个对象的Field设置值.
Method类
它就是类的成员函数对象.可以使用Class类的getDeclaredMethod取得.这个函数需要指明你想要取得的函数对象的参数信息,因为函数可以重载.
例如,如果类A里面声明了两个函数
public int func(int a,int b);
public int func(String a,String b);
那要取得第一个函数对象,就
A a=new A();
Method m1=a.getClass().getDeclaredMethod(“func”,int.class,int.class);
Method m2=a.getClass().getDeclaredMethod(“func”,Class.forName(“java.lang.String”),Class.forName(“java.lang.String”));
取得了Method对象后,可以使用这个Method对象的invoke函数去调用这个函数.
AccessibleObject类
它是那些可访问类的父类,提供类的成员的访问权限信息,也可以运行时修改它的访问权限:isAccessible/setAccessible 查询和设置.对于私有变量/函数,需要先setAccessible为true,然后才能访问.非常规情况下(如破解)时,可以用到.
下面举一个Java反射机制的简单例子程序来结束这篇文章.下一篇文章还没写,估计要一两周才出来吧!
02 | package com.hoverlees.reflect; |
03 | import java.lang.reflect.Field; |
04 | public class ReflectTest { |
05 | public int intVal= 100 ; |
06 | public String strVal= "hoverlees" ; |
11 | public ReflectTest( int a,String b, int c){ |
16 | public void func( int a, int b){ |
17 | System.out.println( "public func(int a,int b) invoked. The sum is:" +(a+b)); |
19 | public void func(String a,String b){ |
20 | System.out.println( "public func(String a,String b) invoked. The sum is:" +(a+b)); |
22 | private void pfunc(String a,String b){ |
23 | System.out.println( "private pfunc(int a,int b) invoked. The sum is:" +(a+b)); |
25 | public int getPrivateValue(){ |
32 | package com.hoverlees.reflect; |
33 | import java.lang.reflect.Constructor; |
34 | import java.lang.reflect.Field; |
35 | import java.lang.reflect.Method; |
38 | public static void main(String[] args){ |
39 | ReflectTest obj= new ReflectTest(); |
53 | Field intf=c.getDeclaredField( "intVal" ); |
54 | intf.setInt(obj, 8766 ); |
55 | Field strf=c.getDeclaredField( "strVal" ); |
56 | strf.set(obj, "lees" ); |
59 | Field privatef=c.getDeclaredField( "pVal" ); |
60 | privatef.setAccessible( true ); |
61 | privatef.setInt(obj, 300 ); |
64 | Method m1=c.getDeclaredMethod( "func" , int . class , int . class ); |
65 | m1.invoke(obj, 10 , 20 ); |
67 | Method m2=c.getDeclaredMethod( "func" , Class.forName( "java.lang.String" ), new String().getClass()); |
68 | m2.invoke(obj, "hover" , "lees" ); |
71 | Method m3=c.getDeclaredMethod( "pfunc" , "" .getClass(),Class.forName( "java.lang.String" )); |
72 | m3.setAccessible( true ); |
73 | m3.invoke(obj, "hover" , "lees" ); |
76 | Constructor ct=c.getConstructor( int . class , "" .getClass(), int . class ); |
77 | ReflectTest obj2=(ReflectTest)ct.newInstance( 1 , "obj2" , 2 ); |
78 | System.out.println( "obj2.intVal=" +obj2.intVal+ ";obj2.strVal=" +obj2.strVal+ ";obj2.pVal=" +obj2.getPrivateValue()); |
79 | } catch (Exception e) { |
83 | System.out.println( "obj.intVal=" +obj.intVal+ ";obj.strVal=" +obj.strVal+ ";obj.pVal=" +obj.getPrivateValue()); |