反射

一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖(反射)出类的各个组成部分。
本人在下面的反射例子中以注释的形式把所理解的东西写了出来

Person类:

 1 import java.util.List;
 2 
 3 public class Person {
 4 
 5     /*
 6      * 1.构造方法
 7      */
 8     //无参的
 9     public Person(){
10         System.out.println("无参的构造方法!");
11     }
12     //一个参数,类型为String的
13     public Person(String name){
14         System.out.println("name:" + name);
15     }
16     //一个参数,类型为int的,且为私有的
17     private Person(int age){
18         System.out.println("age:" + age);
19     }
20     //参数为两个参数
21     public Person(String name, int age){
22         System.out.println(name + "的年龄:" + age + "岁");
23     }
24     //参数为List的
25     public Person(List list){
26         System.out.println("list:" + list);
27     }
28     
29     /*
30      * 2.普通方法
31      */
32     //1、无参
33     public void methodTest(){
34         System.out.println("这是无参的普通方法!");
35     }
36     
37     //2、一个参数
38     public void methodTest(String name){
39         System.out.println("名字:" + name);
40     }
41     //3、一个参数私有的
42     private void methodTest(int age){
43         System.out.println("年龄:" + age);
44     }
45     //4、两个参数静态的
46     public static void methodTest(String name, int age){
47         System.out.println(name + "的年龄:" + age);
48     }
49     //5、main方法
50     public static void main(String[] args) {
51         System.out.println("main方法:");
52     }
53     
54     /*
55      * 3.字段
56      */
57     public String name = "张三";
58     private int age = 25;
59     private static String password = "PaSs1111";
60 }

测试代码:

  1 import java.lang.reflect.Constructor;
  2 import java.lang.reflect.Field;
  3 import java.lang.reflect.InvocationTargetException;
  4 import java.lang.reflect.Method;
  5 import java.util.ArrayList;
  6 import java.util.List;
  7 
  8 import org.junit.Test;
  9 
 10 public class ReflectTest {
 11 
 12     /**
 13      * @功能:反射
 14      * @介绍:
 15      *         clazz1.getConstructor()中的参数是可变参数,
 16      *     且用clazz1.getConstructor()只能反射出public型的,private反射不到
 17      *     如果想要得到private的构造方法,则需要用clazz.getDeclaredConstructor()来反射private的构造函数
 18      * @日期:2013-10-22
 19      */
 20 
 21     /*
 22      * 1.构造方法反射
 23      */
 24     @Test
 25     public void test1() throws Exception{
 26         //加载类(方式一) 参数中类名要全称
 27         Class clazz1 = Class.forName("cn.itcast.reflect.Person");
 28         //加载类(方式二)  ==> 实例化的时候构造方法直接运行
 29 //        Class clazz2 = new Person().getClass();
 30         //加载类(方式三)
 31 //        Class clazz3 = Person.class;
 32         //反射无参的构造方法,null表示无参
 33         Constructor c = clazz1.getConstructor(null);
 34         //new一个对象(正常情况下返回的是Object型的,这里强转为Person)
 35         Person p = (Person) c.newInstance();
 36     }
 37     
 38     @Test
 39     public void test2() throws Exception{
 40         //加载类
 41         Class clazz = Class.forName("cn.itcast.reflect.Person");
 42         //解剖(反射)出参数为String的构造方法(String.class)
 43         Constructor c = clazz.getConstructor(String.class);
 44         c.newInstance("张三");
 45     }
 46     
 47     @Test
 48     public void test3() throws Exception{
 49         //加载类
 50         Class clazz = Class.forName("cn.itcast.reflect.Person");
 51         //解剖(反射)出参数为int的构造方法(int.class)
 52         /*
 53          * 因为此时的构造方法为private的,所以正常的clazz.getConstructor(),不能反射出来
 54          * 此时就要用clazz.getDeclaredConstructor()来反射private的构造函数
 55          * 但解剖出来的构造方法不能直接new一个新的对象,还得能过c.setAccessible(true)修改一下属性(暴力反射)
 56          * ,这时才能进行new新对象,和正常的反射一样了
 57          */
 58         Constructor c = clazz.getDeclaredConstructor(int.class);
 59         //打开访问权限
 60         c.setAccessible(true);
 61         c.newInstance(25);
 62     }
 63     
 64     @Test
 65     public void test4() throws Exception{
 66         //加载类
 67         Class clazz = Class.forName("cn.itcast.reflect.Person");
 68         //反射方法
 69         Constructor c = clazz.getConstructor(String.class,int.class);
 70         //new
 71         c.newInstance("李四",25);
 72     }
 73     
 74     @Test
 75     public void test5() throws Exception{
 76         //加载类
 77         Class clazz = Class.forName("cn.itcast.reflect.Person");
 78         //反射方法
 79         Constructor c = clazz.getConstructor(List.class);
 80         //new
 81         List list = new ArrayList();
 82         list.add("zhangsan");
 83         list.add("lisi");
 84         list.add("wangwu");
 85         list.add("zhaoliu");
 86         c.newInstance(list);
 87     }
 88     
 89     /*
 90      * 2.普通方法反射
 91      */
 92     @Test
 93     public void test6() throws Exception{
 94         Person p = new Person();
 95         //加载类
 96         Class clazz = Class.forName("cn.itcast.reflect.Person");
 97         
 98         /*
 99          * 反射方法【clazz.getMethod("methodTest", null) 第一个参数为:方法名;第二个参数为:方法入参的类型】
100          * 这里方法入参为空,所以用null表示参数类型
101          */
102         Method method = clazz.getMethod("methodTest", null);
103         //method.invoke(p, null) 第一个参数要传一个对象,第二个为所反射的方法入参
104         method.invoke(p, null);
105     }
106     
107     @Test
108     public void test7() throws Exception{
109         Person p = new Person();
110         //加载类
111         Class clazz = Class.forName("cn.itcast.reflect.Person");
112         //反射
113         Method method = clazz.getMethod("methodTest", String.class);
114         //
115         method.invoke(p, "张三");
116     }
117     
118     @Test
119     public void test8() throws Exception{
120         Person p = new Person();
121         //加载类
122         Class clazz = Class.forName("cn.itcast.reflect.Person");
123         //私有的方法要用getDeclaredMethod来反射获取
124         Method method = clazz.getDeclaredMethod("methodTest", int.class);
125         //反射出来的方法此时还是private的,要强制打开访问权限
126         method.setAccessible(true);
127         //
128         method.invoke(p, 25);
129     }
130     
131     @Test
132     public void test9() throws Exception{
133         //加载类
134         Class clazz = Class.forName("cn.itcast.reflect.Person");
135         //反射
136         Method method = clazz.getMethod("methodTest", String.class, int.class);
137         /*
138          * 静态的可以不传对象,为:null即可
139          * (第一个参数为传对象的位置,后边的参数都是把反射方法的入参,invoke的“第二个参数”即为可变参数)
140          */
141         method.invoke(null, "李四", 25);
142     }
143     
144     @Test
145     public void test10() throws Exception{
146         //加载类
147         Class clazz = Class.forName("cn.itcast.reflect.Person");
148         Method method = clazz.getMethod("main", String[].class);
149         //main方法也是个静态方法
150         /*
151          * 关于下边注释的部分,是不可以用的,因为main方法中的参数为String[] args,是一个数组,在这里视为一个参数
152          * 在jdk1.4之前,没有“可变参数”,到了1.5以后才有的可变参数
153          * 那么,jdk1.4之前的method.invoke(String mehtodName, Object obj[])中
154          * 第二个参数用一个数组Object obj[]来传参的,在invoke中会把这个数组拆解成为一个个对应的参数
155          * 而jdk1.5是兼容jdk1.4的,所以,在jdk1.5中用数组来传参也可以,当然,它会把这个数组给拆解成几个参数
156          * 因此,在调用main方法的时候,要在外围再加一个数组,具体如下【数组参数1/2】
157          * 
158          * 注:反射参数为数组的方法都要注意
159          */
160         //method.invoke(null, new String[]{"123","234"});
161         //【数组参数1】
162         method.invoke(null, new Object[]{new String[]{"1234","5678","9012"}});
163         //【数组参数2】也可以这样(前边加一个Object可以欺骗一下程序,骗它为不是数组,其实传进去的确实为数组)
164         method.invoke(null, (Object)new String[]{"1234","5678","9012"});
165     }
166     
167     /*
168      * 3.字段反射
169      */
170     
171     @Test
172     public void test11() throws Exception{
173         Person p = new Person();
174         //加载类
175         Class clazz = Class.forName("cn.itcast.reflect.Person");
176         //参数为字段名称
177         Field field = clazz.getField("name");
178         //获取字段值,传一个对象进去
179         Object obj = field.get(p);
180         //获取字段的类型
181         Class type = field.getType();
182         //如果字段类型为String,则打印数值
183         if(type.equals(String.class)){
184             String value = (String) obj;
185             System.out.println(value);
186         }
187         //设置字段值,第一个参数传一个对象,第二个参数为修改的内容
188         field.set(p, "李四");
189         //打印一下,看看能不能通过反射来改变字段的值(结果:可以)
190         System.out.println(p.name);
191     }
192     
193     @Test
194     public void test12() throws Exception{
195         Person p = new Person();
196         //加载类
197         Class clazz = Class.forName("cn.itcast.reflect.Person");
198         //
199         Field field = clazz.getDeclaredField("age");
200         //私有字段,修改访问权限
201         field.setAccessible(true);
202         System.out.println(field.get(p));
203     }
204     
205     @Test
206     public void test13() throws Exception{
207         Person p = new Person();
208         //加载类
209         Class clazz = Class.forName("cn.itcast.reflect.Person");
210         Field field = clazz.getDeclaredField("password");
211         field.setAccessible(true);
212         /*
213          * 这里,password字段为私有且静态的字段,
214          * 但静态字段不同于静态方法和静态构造方法,field.get(p)中必须传对象
215          */
216         System.out.println(field.get(p));
217     }
218 }

 

posted @ 2013-10-22 17:30  zunpengw  阅读(717)  评论(0编辑  收藏  举报