一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖(反射)出类的各个组成部分。
本人在下面的反射例子中以注释的形式把所理解的东西写了出来java
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 //一、无参 33 public void methodTest(){ 34 System.out.println("这是无参的普通方法!"); 35 } 36 37 //二、一个参数 38 public void methodTest(String name){ 39 System.out.println("名字:" + name); 40 } 41 //三、一个参数私有的 42 private void methodTest(int age){ 43 System.out.println("年龄:" + age); 44 } 45 //四、两个参数静态的 46 public static void methodTest(String name, int age){ 47 System.out.println(name + "的年龄:" + age); 48 } 49 //五、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 }