概念
官方介绍
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
通俗解释
把.class文件加载到内存,并创建对应的Class对象(这是第一步),然后获取Class对象(字节码对象)中的Constructor,Field,Method(这是第二步)。并通过这三个对象任意操作内存中的对象属性和行为(这是第三步)。
名词解释:
Constructor 构造方法描述器
Field 属性描述器
Method 方法描述器
获取Class对象的方式
当Person.class或者Dog.class文件加载到内存后可以得到一个对象,这个对象叫做Class,我们称为字节码对象,.class文件我们称为字节码文件,下面介绍如何把.class文件加载到内存,并得到对应的Class对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class 获取Class对象的三种方式 { public static void main(String[] args) throws Exception { Class clazz = Person.class;
Class clazz2 = Class.forName("cn.itcast.domain.Person");
Class clazz3 = new Person().getClass();
System.out.println(clazz==clazz2); System.out.println(clazz3==clazz2); } }
|
输出都是true,说明同一个.class文件被加载到内存后我们得到的Class对象都是一样的
通过反射操作对象的属性
案例一:通过反射给person对象的name属性赋值,并且在获取name属性的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Person person = new Person("李四", 13);
Class clazz = Person.class;
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(person, "张三");
String name = (String)field.get(person);
System.out.println(name);
|
通过反射操作构造方法
案例一:获取public Person(String name, int age){}构造方法对应的Constructor并创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
constructor.setAccessible(true);
Person person = (Person)constructor.newInstance("张三", 13);
System.out.println(person);
|
案例二:获取public Person(int age, String name){}构造方法对应的Constructor并创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class);
constructor.setAccessible(true);
Person person = (Person)constructor.newInstance(13,"张三");
System.out.println(person);
|
案例三:获取Person()构造方法对应的Constructor并创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| Class clazz = Person.class;
Constructor constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
Person person = (Person)constructor.newInstance();
System.out.println(person);
|
思考
1.getDeclaredConstructor方法应该传入什么参数
2.newInstance方法需要传入什么参数
通过反射操作对象的普通方法
案例一:通过反射调用person对象的public setName(String name){}方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Person person = new Person("张三", 13);
Class clazz = Person.class;
Method setName = clazz.getDeclaredMethod("setName",String.class);
setName.setAccessible(true);
setName.invoke(person,"李四");
System.out.println(person);
|
案例二:通过反射调用person对象的public getName(){}方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Person person = new Person("张三", 13);
Class clazz = Person.class;
Method getName = clazz.getDeclaredMethod("getName");
getName.setAccessible(true);
String name = getName.invoke(person);
System.out.println(name);
|
思考
1.getDeclaredMethod方法应该传入什么参数
2.invoke方法需要传入什么参数
反射案例
通过反射执行配置文件中指定类的指定方法
在src根目录新建配置文件config.properties,内容如下:
1 2
| className=cn.itcast.domain.Student methodName=sleep
|
Student类代码,该类必须放在cn.itcast.domain包下
1 2 3 4 5
| public class Student{ public void sleep(){ System.out.println("睡觉"); } }
|
测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| Properties properties = new Properties();
properties.load(反射的应用真实案例.class.getClassLoader().getResourceAsStream("config.properties"));
String className = properties.getProperty("className"); Class clazz = Class.forName(className);
Constructor constructor = clazz.getDeclaredConstructor(); constructor.setAccessible(true); Object stu = constructor.newInstance();
String methodName = properties.getProperty("methodName"); Method method = clazz.getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(stu);
|
好处
通过反射创建的这个测试类代码通用性非常强,可以执行任意类的任意无参方法。好处就是把项目部署到服务器以后如果想执行其他类的方法,只需要修改服务器上的config.properties配置文件即可。如果按照以前的方式:new Student().sleep()
,想执行其他类的方法那么必须要在开发者电脑上修改源代码,重新编译项目,最后还需要重新上传到服务器,非常麻烦。