java中的反射

要说java中的反射首先得说说java中的类加载机制。首先java源文件通过编译,生成字节码文件存在硬盘上,虚拟及启动后,根据main函数调用到类的先后顺序动态的加载类到内存,加载有一个原则,首先加载bootstrap classloader:系统类的类加载器;再加载ExtClassLoader:系统中一部分的类加载器;最后是AppClassLoader:应用程序中自己定义的类加载器。三者的关系依次是parentclassloader的关系。因此,在classloader看来,加入内存的类的字节码也是一个个的对象,因此也应该有抽象出来的共性,所以就引出了Class类,Class类是所有字节码类的抽象的结果,每个类中都有的因素比如属性,方法等。而将类中的这些成员抽象成类就是反射。用反射我们可以动态的去加载一个类,动态的去了解一个类。因此可以说反射是java动态编程的重要一部分。

这里先简要的说说class中反射出的method类,field类,constructor类。

1.

要生成类对象,一个大众的方法就是通过constructor类生成对应构造函数参数的constructor类,再通过constructor类的newInstance()方法传入刚设置的参数,最后生成这个类的实例。

 1 package reflect;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Method;
5
6 public class TestReflect {
7
8 public static void main(String[] args) throws Exception {
9 // TODO Auto-generated method stub
10 Class<?> c = Class.forName("reflect.Test1");//通过反射得到名字为Reflect.Test1的类对象
11 Test1 test11 = (Test1)c.newInstance();//创建Test的实例 无参
12 test11.show1();
13 Constructor<?> cons = c.getConstructor(int.class);
14 Test1 test12 = (Test1)cons.newInstance(1000);
15 test12.show1();
16 System.out.println("------------------");
17
18 Method m = c.getMethod("show2"); //用get方法只能得到声明为public的成员
19 m.invoke(null);//静态方法不通过对象
20
21 /*Method[] methods = c.getMethods();
22 for(Method m : methods){
23 System.out.println(m.getName());//只有public的method方法才可见
24 }*/
25
26 }
27
28 }
29
30 class Test1{
31 static String s1 ="aaaabb";
32 static int i =100;
33 public Test1() {
34 System.out.println("no parameter constructor");
35 }
36 public Test1(int i){
37 this.i = i;
38 System.out.println("Test1 constructor");
39 }
40 //如果需要开放最好设置为public权限
41 public static void show2(){
42 System.out.println(i + " " +s1);
43 }
44
45 public void show1 (){
46 System.out.println(s1 + " " +i);
47 }
48 @Override
49 public String toString(){
50 return null;
51 }
52 }

 

这里要说明,通过constructor类生成的对象,一般都是自己找的构造函数的生成的对象,如果生成的类需要在构造函数中初始化的话一般用这中方法。而class类中也有newInstance()方法,其实就用简略的方法直接实现了无参数的构造函数生成对象。上例中通过打印结果可以看出结果,而且还可以验证了静态代码块在类加载内存的只执行一次,构造函数和构造代码块在每次生成对象都会调用一次。

2.

field类是表示类中的成员属性,这里通过对一个类中的所有的string成员属性进行字符串替换学习:

 

 1 package reflect;
2
3 import java.lang.reflect.Field;
4
5 //用反射实现,将任意一个对象成员中string成员中的"eng"换成字符"cn"。
6
7 public class TestReflect1 {
8
9 public static void main(String[] args) throws Exception {
10 Class c = Class.forName("reflect.Test2");
11 Field[] fields = c.getFields();
12 Test2 test21 = (Test2)c.newInstance();
13 test21.show();
14 System.out.println("------------------");
15 for(Field f : fields){
16 // System.out.println(f.getName());
17 if (f.getType().equals(String.class)) {
18 // System.out.println(f.getType().getName());
19 String s = (String)f.get(test21);
20 if(s.contains("eng")){
21 s = s.replace("eng", "chn");
22 }
23 f.set(test21, s);
24 }
25
26 }
27 test21.show();
28 }
29
30 }
31
32 class Test2{
33 //public
34 public String s1 = "i am eng";
35 public String s2 = "i from eng";
36 void show (){
37 System.out.println(s1 + "\n" +s2);
38 }
39
40 }

通过两个例子,我们大概可以看出class类的一些使用规律,比如a:getXXX返回的一般是一个数组型的,里面包含了所有了这个属性的值,后续操作的时候要先判断是自己要用的那个属性;b:getdeclaredXXX的返回的是按照自己设置的存在的,而且以后使用的时候只能按照取出来的时候的规则使用。c:因为定义的时候并不知道返回的是什么值,所以这部分需要相当一部分的类型转换。

3.

Method类,也遵循上述总结的规律,这里也用例子直接说明:

 1 package reflect;
2
3 import java.lang.reflect.Method;
4
5 public class TestReflect2 {
6
7 public static void main(String[] args) throws Exception {
8 // TODO Auto-generated method stub
9 // TestMethod.main("11","22","33");//直接传入字符串
10 TestMethod.main(new String[]{"99","88","77"});//传入字符串数组
11
12 Method m = Class.forName("reflect.TestMethod").getDeclaredMethod("main", String[].class);
13 /*
14 理解难点,因为这里原来是string[],而且并不知道传入的参数的个数,所以这里解决方法是把他看作是一个string[]的整体,
15 而这个整体的就可以匹配未定义长度的string[],所以这里string[]其实是当作一个参数看待的
16 */
17 // m.invoke(null, new String[]{"11","22","33"});//因为string不是基本类型,所以函数认为传了三个参数进去,但是只应该传一个进去
18 m.invoke(null, new Object[]{new String[]{"11","22","33"}});
19 m.invoke(null, (Object)new String[]{"11","22","33"});
20
21 }
22
23 }
24
25 class TestMethod{
26 static void main(String[] args){
27 int i = 0;
28 for(String s : args){
29 System.out.println((i++)+" : "+s);
30 }
31 }
32 }

这里也有一个理解上的难点,就是注释的部分。我现在理解的也不是很透彻,注释部分按照目前的理解分享出来,以后有新心得在补充。

 

然后看到javabean的内省,按照目前的理解是内省是一种特殊的反射,即成员属性,成员方法比较有规律的一种情况?以后学习完整了新开文章分析。


 

 

posted @ 2012-03-26 00:19  ruidge  阅读(470)  评论(0编辑  收藏  举报