Class类与java.lang.reflect类库一起对反射进行了支持,该类库包含Field、Method和Constructor类,这些类的对象由JVM在启动时创建,用以表示未知类里对应的成员。这样的话就可以使用Contructor创建新的对象,用get()和set()方法获取和修改类中与Field对象关联的字段,用invoke()方法调用与Method对象关联的方法。另外,还可以调用getFields()、getMethods()和getConstructors()等许多便利的方法,以返回表示字段、方法、以及构造器对象的数组,这样,对象信息可以在运行时被完全确定下来,而在编译时不需要知道关于类的任何事情。
首先创建一个类
1 public class Per { 2 public String name="sunshine"; 3 private int age=28; 4 public double weight=65.50; 5 6 public Per(){ 7 System.out.println("测试反射获取公有无参构造函数"); 8 } 9 private Per(String name){ 10 this.name=name; 11 System.out.println("测试反射获取私有有参构造函数"); 12 } 13 public Per(String name,int age){ 14 this.name=name; 15 this.age=age; 16 System.out.println("测试反射获取公有有多个参数构造函数name:"+name+" age:"+age);17 } 18 public String methodT1(){ 19 System.out.println("测试反射获取公有无参方法"); 20 return null; 21 } 22 public String methodT1(String name,int age){ 23 System.out.println("测试反射获取公有多个参方法"); 24 System.out.println(name+":"+age); 25 return null; 26 } 27 private String methodT1(String name){ 28 System.out.println("测试反射获取私有有参方法"); 29 System.out.println("name:"+name); 30 return null; 31 } 32 public String methodT2(int[] arr,String[] str){ 33 System.out.println("测试反射获取公有有数组参方法"); 34 System.out.println("int[] arr:"+arr+"String[] str:"+str); 35 return null; 36 } 37 public static void main(String[] args) { 38 System.out.println("测试反射获取main方法"); 39 } 40 }
1.使用java反射获取类的构造函数(公有、私有)(有参,无参)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 import org.junit.AfterClass; 6 import org.junit.BeforeClass; 7 import org.junit.Test; 8 /** 9 * 测试使用java反射获取类的构造函数并创建对象 10 * @author Sunshine 11 * 12 */ 13 public class ReflectPer { 14 private static Class class1; 15 //因为java反射获取类时都需要加载类,在这里我就使用Junit的@beforeclass来去加载类,不用在每个测试方法中重复创建 16 //注:@beforeclass在执行测试方法前运行 17 @BeforeClass 18 public static void beforeClass() throws Exception{ 19 System.out.println("====测试方法启动前先加载类===="); 20 class1 = Class.forName("myPractise.Per");//加载类 21 } 22 //获取类的公有无参构造函数,并创建对象 23 @Test 24 public void test1() throws Exception{ 25 Constructor constructor = class1.getConstructor(null);//获取公有无参构造器,值为null代表获取无参构造器 26 Per per = (Per) constructor.newInstance(null);//创建对象,返回的是Object类型要强转 27 System.out.println(per.name);//可以调用类的属性-----成功 28 } 29 //获取类的公有参构造函数,并创建对象 30 @Test 31 public void test2()throws Exception{ 32 Constructor constructor = class1.getConstructor(String.class,int.class);//获取公有多个参数构造器,参数为构造器中参数的类型 33 Per per = (Per)constructor.newInstance("baby",24);//创建对象 34 } 35 //获取类的私有有参构造函数,并创建对象 36 @Test 37 public void test3()throws Exception{ 38 Constructor constructor = class1.getDeclaredConstructor(String.class);//获取公有多个参数构造器,参数为构造器中参数的类型 39 constructor.setAccessible(true);//暴力反射,只有将属性设置为true才可以创建对象 40 Per per = (Per)constructor.newInstance("baby"); 41 System.out.println(per.weight);//可以调用类的属性-----成功 42 //注:通常情况下一个类不可以访问另一个类的私有的属性,方法。。但是通过java反射可以 43 } 44 @AfterClass 45 public static void afterClass(){ 46 System.out.println("===测试完成将对象赋值为null==="); 47 } 48 }
2.使用java反射获取类的方法(公有、私有)(有参,无参)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 5 import org.junit.AfterClass; 6 import org.junit.BeforeClass; 7 import org.junit.Test; 8 /** 9 * 测试使用java反射获取类方法 10 * @author Sunshine 11 * 12 */ 13 public class ReflectPer { 14 private static Class class1; 15 private static Per per; 16 //因为java反射获取类时都需要加载类,在这里我就使用Junit的@beforeclass来去加载类,不用在每个方法中重复创建 17 //注:@beforeclass在执行测试方法前运行 18 @BeforeClass 19 public static void beforeClass() throws Exception{ 20 System.out.println("====测试方法启动前先加载类===="); 21 class1 = Class.forName("myPractise.Per");//加载类 22 per = (Per) class1.getConstructor(null).newInstance(null);//使用反射创建对象 23 } 24 25 //获取类的公有无参方法 26 @Test 27 public void test4()throws Exception{ 28 Method method = class1.getMethod("methodT1", null);//获取指定的方法,参数为方法名和该方法的参数类型,因为我们这是测试无参的方法,所以传入null 29 method.invoke(per, null);//使用invoke方法来调用,参数为指定对象,该方法传入的参数,因为我们这是测试无参的方法,所以传入null 30 } 31 //获取类的公有有参方法 32 @Test 33 public void test5()throws Exception{ 34 Method method = class1.getMethod("methodT1", String.class,int.class);//获取指定的方法,参数为方法名和该方法的参数类型 35 method.invoke(per, "sunshine",25);//使用invoke方法来调用,参数为指定对象,该方法传入的参数 36 } 37 @Test 38 public void test6()throws Exception{ 39 Method method = class1.getDeclaredMethod("methodT1", String.class);//获取指定的方法,参数为方法名和该方法的参数类型 40 method.setAccessible(true);//暴力反射,默认为false,未设置则调用类的私有方法不成功 41 method.invoke(per, "sunshine");//使用invoke方法来调用,参数为指定对象,该方法传入的参数 42 System.out.println(method.getReturnType());//获取到该类指定方法的返回值类型 43 } 44 @Test 45 public void test7()throws Exception{ 46 Method method = class1.getMethod("methodT2", int[].class,String[].class); 47 method.invoke(per, new int[]{1,2},new String[]{"AA","BB"}); 48 } 49 //获取某个类的main方法比较特殊也可以说是只要传入的参数为单个数组特殊 50 //jdk5之后新增特性--可变参数 51 //在加载时会将传入的数组进行拆分,这样就会报错,java.lang.IllegalArgumentException: wrong number of arguments 错误的参数个数 52 //这时候我们可以欺骗一下虚拟机,告诉他我们传入的是一个对象将new String[]{"AA","BB"}换成(Object)new String[]{"AA","BB"} 53 @Test 54 public void test8()throws Exception{ 55 Method method = class1.getMethod("main",String[].class); 56 method.invoke(per,(Object)new String[]{"AA","BB"}); 57 } 58 @AfterClass 59 public static void afterClass(){ 60 System.out.println("===测试完成将对象赋值为null==="); 61 } 62 }
3.使用java反射获取类的属性(公有、私有)
1 import java.lang.reflect.Constructor; 2 import java.lang.reflect.Field; 3 import java.lang.reflect.Method; 4 import java.util.Iterator; 5 6 import org.junit.AfterClass; 7 import org.junit.BeforeClass; 8 import org.junit.Test; 9 10 /** 11 * 测试使用java反射获取类的属性 12 * 13 * @author Sunshine 14 * 15 */ 16 public class ReflectPer { 17 private static Class class1; 18 private static Per per; 19 20 // 因为java反射获取类时都需要加载类,在这里我就使用Junit的@beforeclass来去加载类,不用在每个测试方法中重复创建 21 // 注:@beforeclass在执行测试方法前运行 22 @BeforeClass 23 public static void beforeClass() throws Exception { 24 System.out.println("====测试方法启动前先加载类===="); 25 class1 = Class.forName("myPractise.Per");// 加载类 26 per = (Per) class1.getConstructor(null).newInstance(null);// 使用反射创建对象 27 } 28 // 公有属性 29 @Test 30 public void test9() throws Exception { 31 // 获取某个属性,参数是属性名 32 Field field = class1.getField("name"); 33 // 输出属性值,需要传入指定对象 34 System.out.println(field.get(per)); 35 // 获取属性的类型 36 System.out.println(field.getType()); 37 // 获取多个属性 38 Field[] field1 = class1.getFields(); 39 // 增强for循环Jdk1.5后的新特性,只适用于数组和实现了Iterator的集合 40 for (Field str : field1) { 41 System.out.println(str); 42 } 43 // 设置属性值 44 field.set(per, "baby"); 45 System.out.println(field.get(per)); 46 } 47 //私有属性 48 @Test 49 public void test10() throws Exception { 50 Field field = class1.getDeclaredField("age"); 51 field.setAccessible(true);//暴力反射 52 System.out.println(field.get(per)); 53 } 54 55 @AfterClass 56 public static void afterClass() { 57 System.out.println("===测试完成将对象赋值为null==="); 58 } 59 }