Java反射机制及应用(一)

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反射机制的简单例子程序来结束这篇文章.下一篇文章还没写,估计要一两周才出来吧!

01//ReflectTest.java
02package com.hoverlees.reflect;
03import java.lang.reflect.Field;
04public class ReflectTest {
05    public int intVal=100;
06    public String strVal="hoverlees";
07    private int pVal=200;
08    public ReflectTest(){
09 
10    }
11    public ReflectTest(int a,String b,int c){
12        intVal=a;
13        strVal=b;
14        pVal=c;
15    }
16    public void func(int a,int b){
17        System.out.println("public func(int a,int b) invoked. The sum is:"+(a+b));
18    }
19    public void func(String a,String b){
20        System.out.println("public func(String a,String b) invoked. The sum is:"+(a+b));
21    }
22    private void pfunc(String a,String b){
23        System.out.println("private pfunc(int a,int b) invoked. The sum is:"+(a+b));
24    }
25    public int getPrivateValue(){
26        return pVal;
27    }
28}
29 
30//Main.java
31 
32package com.hoverlees.reflect;
33import java.lang.reflect.Constructor;
34import java.lang.reflect.Field;
35import java.lang.reflect.Method;
36public class Main {
37    //不要把main写在ReflectTest类里,不然它本来就可以直接访问ReflectTest里的私有属性.
38    public static void main(String[] args){
39        ReflectTest obj=new ReflectTest();
40        Class c=null;
41        c=obj.getClass();
42        /*
43        //或者使用这种方法取得Class.
44        try {
45            c = Class.forName("com.hoverlees.reflect.ReflectTest");
46        } catch (ClassNotFoundException e1) {
47            e1.printStackTrace();
48            return;
49        }
50        */
51        try {
52            //访问正常属性
53            Field intf=c.getDeclaredField("intVal");
54            intf.setInt(obj, 8766); // obj.intVal=8766;
55            Field strf=c.getDeclaredField("strVal");
56            strf.set(obj, "lees"); //obj.strVal="lees";
57 
58            //强制访问obj.pVal,正常情况下是不可访问的.注:此方法违背面向对象思想,正常情况不推荐使用
59            Field privatef=c.getDeclaredField("pVal");
60            privatef.setAccessible(true);
61            privatef.setInt(obj, 300); //obj.pVal=300;
62 
63            //访问函数
64            Method m1=c.getDeclaredMethod("func", int.class,int.class);
65            m1.invoke(obj, 10,20); //obj.func(10,20);
66            //下面用了Class.forName和object.getClass(),只是为了再次强调它们的效果是一样的.在不同的场合下,用不同的方法.
67            Method m2=c.getDeclaredMethod("func", Class.forName("java.lang.String"),new String().getClass());
68            m2.invoke(obj, "hover","lees");
69 
70            //强制问题私有函数,这儿举例的 "".getClass() 还是相当于new String().getClass().
71            Method m3=c.getDeclaredMethod("pfunc", "".getClass(),Class.forName("java.lang.String"));
72            m3.setAccessible(true);
73            m3.invoke(obj,"hover", "lees");
74 
75            //再举个构造函数的例子
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) {
80            e.printStackTrace();
81        }
82 
83        System.out.println("obj.intVal="+obj.intVal+";obj.strVal="+obj.strVal+";obj.pVal="+obj.getPrivateValue());
84    }
85}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值