相信大家经常听说某些框架设计用到了反射机制啥啥,但自己对此概念却了解甚少,虽然一般开发不会用到,但还是有必要知道反射的基本原理和操作。
  使用反射,可以做到:
- 在运行中分析类的能力。
 
- 在运行中查看对象,例如,编写一个toString方法供所有类使用。
 
- 实现数组的操作代码。
 
- 利用Method对象,这个对象很像C++中的函数指针。
 
反射操作主要用到的类有Class(类)、Field(属性)、Method(成员函数)、Constructor(构造)和Modifier(修饰符)
一、反射获取类
新建一个Student类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
   | public class Student {
  	private int age; 	private String name; 	 	 	public Student() { 		 	} 	 	 	public Student(int age, String name){ 		this.age = age; 		this.name = name; 		System.out.println("My name is "+name+",I'm "+age+" years old."); 	} 	 	public void setAge(int age) { 		this.age = age; 	} 	public void setName(String name) { 		this.name = name; 	} 	 	public int getAge() { 		return age; 	} 	public String getName() { 		return name; 	} 	 	public void learning() { 		System.out.println("learning..."); 	} 	 }
  | 
 
测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
   | public class ReflexTest { 	public static void main(String[] args) throws ClassNotFoundException { 		Student student = new Student(20, "shen");//一般创建对象 		 		Class stu = Class.forName("com.test.reflex.Student");//通过Class获取指定类的完整结构 		System.out.println("getName--->"+stu.getName()); 		 		Student s = null; 		Student s1 = null;  		try { 			s = (Student)stu.newInstance();//默认构造的是无参构造,若存在有参构造,这里将报错 			 			Constructor constructor = stu.getConstructor(int.class, String.class);//获取有参构造,已知确定参数 			s1 = (Student)constructor.newInstance(23, "shen");//有参构造 			 			Constructor[] constructors = stu.getConstructors();//所有构造 			s1 = (Student)constructors[0].newInstance();//第一个构造(无参那个) 		} catch (Exception e) { 			e.printStackTrace(); 		} 		 	} }
  | 
 
输出:

Class类forName方法通过完整包路径类型来实例化Class对象,再通过Class对象获取Student类实例;
再使用newInstance()创建对象,这里要注意Student的构造方法,默认使用的试试无参构造,可使用Constructor类操作构造方法。
二、获取类的基本结构
1、使用反射操作对象属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | public class Test01 { 	public static void main(String[] args) throws Exception, Exception { 		try { 			Class stu = Class.forName("com.test.reflex.Student"); 			 			Constructor constructor = stu.getConstructor(int.class, String.class);//获取有参构造,已知确定参数 			Student s = (Student)constructor.newInstance(23, "shen");//有参构造 			 			//Field[] fields = stu.getFields();//获取public的属性 			Field[] fields = stu.getDeclaredFields();//获取所有属性 			for(Field field : fields){ 				System.out.println("属性-->"+field); 			} 			 			Field fieldName = stu.getDeclaredField("name");//获取私有变量name 			fieldName.setAccessible(true); 			System.out.println(fieldName.getName());//私有属性名称 			System.out.println(fieldName.get(s));//私有属性值 			 			fieldName.set(s, "a-shen"); 			System.out.println(fieldName.get(s));//改变私有属性值 			 		} catch (ClassNotFoundException e) { 			e.printStackTrace(); 		} 		 	} }
  | 
 
结果输出

其中对于fieldName.setAccessible(true);使用java反射获取类的属性值时,如果该属性被声明为private 的,需要将setAccessible设置为true. 默认的值为false
2、使用反射访问成员函数
通过反射调用方法,使用invoke方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
   | public class Test02 { 	public static void main(String[] args) throws Exception, Exception { 		try { 			Class stu = Class.forName("com.test.reflex.Student"); 			 			Constructor constructor = stu.getConstructor(int.class, String.class);//获取有参构造,已知确定参数 			Constructor[] constructors = stu.getConstructors(); 			Student s = (Student)constructors[0].newInstance();//无参构造对象 			 			//Method[] methods = stu.getMethods();//获取类所有方法,包括继承自父类和实现接口的方法 			Method[] methods = stu.getDeclaredMethods();//获取类本身各类方法和实现接口的方法及重写的方法,不包括继承的方法 			for(Method method : methods){ 				System.out.println("成员函数--->"+method); 			} 			 			Method m1 = s.getClass().getMethod("setName", String.class); 			m1.invoke(s, "ashen");//设置name值为"ashen" 			 			Method m2 = s.getClass().getMethod("getName"); 			String name = (String) m2.invoke(s); 			System.out.println("getName--->"+name);//输出name值 			 		}catch (ClassNotFoundException e) { 			e.printStackTrace(); 		} 		 	} }
  | 
 
结果输出
