当我们编写的类生成的字节码文件中的二进制字节流被类加载器加载到内存当中时,会在方法区产生一个Class对象,作为访问这些类信息的入口。
假如我们编写一个Person类,获取Class对象一般有3种方式:
- 通过类名本身:
Class clazz = Person.class;
- 通过实例变量的方式:
Class clazz = new Person().getClass();
- 通过Class的静态方法Class.forName(String classname)(需加上try…catch,可能会抛ClassNotFoundException异常)。
Class clazz = Class.forName("com.wgs.reflecttest.Person");
forName方法会调用Native方法forName0(),在JVM中会调用findClassFromClassLoader()去加载Person类,触发Person类的构造器初始化。 - 在上述创建了类对象以后,Class有一个方法可以创建类对象的实例:
public T newInstance() throws InstantiationException, IllegalAccessException
注:它会调用类的默认构造方法(即无参public构造方法),如果类没有该构造方法,会抛出异常InstantiationException。
获取Field字段信息
Class有4个获取字段信息的方法,包括静态变量和实例变量:
所有的public字段,包括其父类的,如果没有字段,返回空数组public Field[] getFields()
//返回本类声明的所有字段,包括非public的,但不包括父类的
public Field[] getDeclaredFields()
//返回本类或父类中指定名称的public字段,找不到抛出异常NoSuchFieldException
public Field getField(String name)
//返回本类中声明的指定名称的字段,找不到抛出异常NoSuchFieldException
public Field getDeclaredField(String name)
当然还可以获取Filed的权限修饰符,类型及属性名等信息。
获取Method类方法信息
类中定义的静态和实例方法都被称为方法,用类Method表示,Class有四个获取方法信息的方法:
本类和父类所有public方法(包括Object的7个方法)
public Method[] getMethods()
//只返回本类声明的所有方法
public Method[] getDeclaredMethods()
//返回本类或父类中指定名称和参数类型的public方法,找不到抛出异常NoSuchMethodException
public Method getMethod(String name, Class<?>... parameterTypes)
//返回本类中声明的指定名称和参数类型的方法,找不到抛出异常NoSuchMethodException
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
Method有个invoke()方法,可以调用对象的方,这个invoke()也是很常用的方法,动态代理就用到了方法:
Method method = XXX.class.getDeclaredMethod(xx,xx);
method.invoke(target,params)
获取构造器信息,并创建运行时的类的对象
所有的public构造方法,返回值可能为长度为0的空数组public Constructor<?>[] getConstructors()
//获取所有的构造方法,包括非public的
public Constructor<?>[] getDeclaredConstructors()
//获取指定参数类型的public构造方法,没找到抛出异常NoSuchMethodException
public Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取指定参数类型的构造方法,包括非public的,没找到抛出异常NoSuchMethodException
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
构造器信息
Constructor constructor = clazz.getConstructor(String.class, int.class);
//创建运行时的类的对象
constructor.newInstance("Tom", 10);
应用一:使用反射机实现简单的设值注入过程
/** * Created by Lance on 2018/3/16. */ public class InjectDemo { public void inject() { try { //反射获取Person类的Class对象,作为在方法区访问类信息的入口 // Class pClazz = Person.class; Class pClazz = Class.forName("reflect.Person"); //创建Person实例 Person person = (Person) pClazz.newInstance(); //反射注入过程 //获取name的setter方法,利用反射注入值 Method setNameMethod = pClazz.getMethod("setName", String.class); setNameMethod.invoke(person, "xiao ming"); //获取age的setter方法,利用反射注入值 Method setAgeMethod = pClazz.getMethod("setAge", Integer.class); setAgeMethod.invoke(person, 19); //打印,是否注入成功 System.out.println(person.getName() + "," + person.getAge()); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static void main(String[] args) { new InjectDemo().inject(); } } class Person { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } }
应用二:使用反射机制+注解实现Spring依赖注入的过程
/** * Created by Lance on 2018/3/16. * 写一个自己的注解 */ @Documented @Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface WGSAnnotation { public String nation() default ""; }
/** * Created by Lance on 2018/3/16. * 写一个接口,以及两个不同的实现类,后期注入不同的类 */ @WGSAnnotation public class UserService { private User userDao; @WGSAnnotation(nation = "EnglishUser") public User getUserDao() { return userDao; } public void setUserDao(User userDao) { this.userDao = userDao; } public void login() { userDao.login(); } }
/** * Created by Lance on 2018/3/16. * 通过反射+注解实现注入过程 */ public class BeanContainer { public static UserService getBean() throws Exception { Class clazz = UserService.class; UserService userService = (UserService) clazz.newInstance(); Class<WGSAnnotation> annotationClass = WGSAnnotation.class; if(clazz.isAnnotationPresent(annotationClass)) { Method[] methods = clazz.getDeclaredMethods(); for(Method m: methods) { //方法上面有注解,就能获取其方法并调用set值,将注解中的值注入进去 if(m.isAnnotationPresent(annotationClass)) { WGSAnnotation annotation = m.getAnnotation(annotationClass); System.out.println("方法" + m.getName() + "开始注入过程" + annotation.nation()); //获取注解实例,注入 User user = (User) Class.forName("reflect." + annotation.nation()).newInstance(); userService.setUserDao(user); } } }else { System.out.println("类上无注解!"); } return userService; } }
/** * Created by Lance on 2018/3/16. * 测试类 */ public class Main { public static void main(String[] args) throws Exception { UserService userService = new BeanContainer().getBean(); userService.login(); } }