反射
这里推荐一篇很好的文章:文章链接
反射:框架设计的灵魂。
框架:半成品软件。可以在框架基础上进行软件开发,简化编码
将类的各个组成部分封装为其他对象,这就是反射机制
(具体讲解 )
反射的优点:
可以在程序运行过程中操作这些对象
可以解耦(降低程序的耦合性),提高程序的可扩展性
Class对象
关于Java中的Class对象,我们可以看一篇入门文章 ,也可以查看jdk1.8api文档
获取Class对象的方式
Class.forName(“类名”) 将字节码文件加载进内存,返回Class对象(多用于配置文件,将类名定义在配置文件中。读取文件、加载类)
类.class 通过类的属性class获取Class对象(多用于参数的传递)
对象.getClass() getClass为Object类中定义的方法(多用于去获取具体对象的字节码文件)
例子:首先创建Person类,代码如下:
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 37 38 39 40 41 package domain;public class Person { private String name; private int age; @Override public String toString () { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}' ; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public Person (String name, int age) { this .name = name; this .age = age; } public Person () { } }
然后创建启动类代码如下:
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 package demo02;import domain.Person;public class Demo01 { public static void main (String[] args) throws ClassNotFoundException { Class<?> aClass1 = Class.forName("domain.Person" ); System.out.println(aClass1); Class aClass2 = Person.class ; System.out.println(aClass2); Person person = new Person(); Class<? extends Person> aClass3 = person.getClass(); System.out.println(aClass3); System.out.println(aClass1==aClass2); System.out.println(aClass3==aClass2); } }
Class对象的相关方法:
具体可查看查看jdk1.8api文档
获取功能:
1.获取成员变量
Filed[] getFileds() 获取所有public修饰的成员变量
Filed[] gerFiled(String name) 获取指定名称的public修饰的成员变量
Filed[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Filed[] getDeclaredField(String name) 获取指定名称的成员变量,不考虑修饰符
2.获取构造方法
Constructor<?>[] getConstructors()
Constructor getConstructor(类<?>… parameterTypes)
Constructor<?>[] getDeclaredConstructors()
Constructor getDeclaredConstructor(类<?>… parameterTypes)
3.获取成员方法:
Method[] getMethods()
Method getMethod(String name, 类<?>… parameterTypes)
Method[] getDeclaredMethods()
Method getDeclaredMethod(String name, 类<?>… parameterTypes)
4.获取全类名
成员变量(Field)的方法:
void set(Object obj,Object value) 设置值
get(Object obj) 获取值
setAccessible(true) 忽略访问权限修饰符的安全检查
构造方法(Constructor)的方法:
T newInstance(Object… args) 创建对象(如果使用空参数构造方法创建对象,操作可以简化为:Class对象的newInstance方法)
方法(Method)的方法:
Object invoke(Object object,Object… args) 执行方法
String getName 获取方法名
成员变量
详细讲解
例子:还是对应上述的Person类,先添加成员变量public int id;
,然后我们创建启动类如下:
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 package demo02;import domain.Person;import java.lang.reflect.Field;public class Demo02 { public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException { Class personClass = Person.class ; Field id = personClass.getDeclaredField("id" ); System.out.println(id); Person person = new Person(); Object idValue = id.get(person); System.out.println(idValue); id.set(person,101 ); Object newIdValue = id.get(person); System.out.println("重新设置后id为:" +newIdValue); System.out.println(person); Field age = personClass.getDeclaredField("age" ); age.setAccessible(true ); Person person2 = new Person("jj" , 28 ); Object ageValue = age.get(person2); System.out.println(ageValue); } }
构造方法
详细讲解
例子:基于上述Person类,创建启动类如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package demo02;import domain.Person;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;public class Demo03 { public static void main (String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class personClass = Person.class ; Constructor personClassConstructor = personClass.getConstructor(String.class , int .class ) ; System.out.println(personClassConstructor); Object person = personClassConstructor.newInstance("jay" , 28 ); System.out.println(person); } }
成员方法
详细讲解
例子:基于上述Person类,我们添加一个study方法()
1 2 3 4 5 6 public void study () { System.out.println("开始学习" ); } public void study (String name) { System.out.println("开始学习" +name); }
然后创建启动类,代码如下:
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 package demo02;import domain.Person;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Demo04 { public static void main (String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Class personClass = Person.class ; Person person = new Person(); Method study_method = personClass.getMethod("study" ); study_method.invoke(person); Method study_method2 = personClass.getMethod("study" , String.class ) ; study_method2.invoke(person,"java" ); String study_methodName = study_method.getName(); System.out.println(study_methodName); } }
案例
需求:写一个”框架“,在不能改变该类代码的前提下,可以帮我们创建任意类的对象,并且执行其中任意方法。
实现:
步骤:
将需要创建的对象的全类名和需要执行的方法定义在配置文件中
在程序中加载读取配置文件
使用反射技术来加载类文件进内存
创建对象
执行方法
实例:
首先创建配置文件如下:
1 2 className = domain.Person methodName = study
然后创建ReflectTest.java类,代码如下:
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 package demo03;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Properties;public class ReflectTest { public static void main (String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { Properties properties = new Properties(); ClassLoader classLoader = ReflectTest.class .getClassLoader () ; InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties" ); properties.load(resourceAsStream); String className = properties.getProperty("className" ); String methodName = properties.getProperty("methodName" ); Class aClass = Class.forName(className); Object obj = aClass.newInstance(); Method method = aClass.getMethod(methodName); method.invoke(obj); } }
这样,我们就可以利用反射,只需要修改配置文件,就可以修改要执行的类以及方法了。