JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
Class反射机制
- 指的是可以于运行时加载,探知和使用编译期间完全未知的类.
- 程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已经加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用他的任意一个方法和属性;
- 加载完类之后,在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象),这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射。
- 每个类被加载进入内存之后,系统就会为该类生成一个对应的java.lang.Class对象,通过该Class对象就可以访问到JVM中的这个类.
Class对象的获取
- 对象的getClass()方法;
- 类的.class(最安全/性能最好)属性;
- 运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用).
- package com.lwl.reflect;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- /**
- * 获取类的所有属性和方法及构造器
- * @create 2017-10-11 上午11:42:52
- * @version 1.0
- */
- public class ReflectAllDemo {
- /**
- * 获取类的所有属性和方法及构造器
- * @param args
- * @throws ClassNotFoundException
- * @create 2017-10-11 上午9:07:46
- */
- public static void main(String[] args) throws ClassNotFoundException {
- //根据一个类的全名称获取类的类对象
- //如果类的全名称错误或者不存在,则会报类查询不到异常:ClassNotFoundException
- Class<?> clazz = Class.forName("java.lang.String");
- //获取传递过来的类的所有方法
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods) {
- System.out.println(method.toString());
- }
- System.out.println("------------------------------我是分隔符:以下是类的属性--------------------------------");
- //获取传递过来的类的所有属性
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- System.out.println(field.toString());
- }
- System.out.println("------------------------------我是分隔符:以下是构造方法--------------------------------");
- //获取传递过来的类的所有构造方法
- Constructor<?>[] constructor = clazz.getDeclaredConstructors();
- for (Constructor<?> ctt : constructor) {
- System.out.println(ctt.toString());
- }
- }
- }
创建对象
通过反射来生成对象的方式有两种:
- 使用Class对象的newInstance()方法来创建该Class对象对应类的实例(这种方式要求该Class对象的对应类有默认构造器).
- 先使用Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建该Class对象对应类的实例(通过这种方式可以选择指定的构造器来创建实例).
调用方法
当获取到某个类对应的Class对象之后,就可以通过该Class对象的getMethod来获取一个Method数组或Method对象.
每个Method对象对应一个方法,在获得Method对象之后,就可以通过调用invoke方法来调用该Method对象对应的方法.
- package com.lwl.reflect;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通过反射,对类中的方法进行操作
- * @create 2017-10-11 上午11:45:57
- * @version 1.0
- */
- public class ReflectMethodDemo {
- public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- //获取对象
- Object instance = clazz.newInstance();
- // instance = clazz.getDeclaredConstructor(null).newInstance(null);
- //如果已经知道方法的名称,那么调用起来更加方便
- Method method = clazz.getDeclaredMethod("setName", new Class[]{String.class});
- //设置值
- method.invoke(instance, new String[]{"jack"});
- System.out.println(instance.toString());
- //获取值
- Method getMethod = clazz.getDeclaredMethod("getName", new Class[]{});
- Object getValue = getMethod.invoke(instance, new String[]{});
- System.out.println(getValue);
- //对对象中的静态方法进行访问
- Method staticMethod = clazz.getDeclaredMethod("printInfo", new Class[]{});
- //由于是静态方法,所以这里面的 instance 可以不传,只用用 null 表示
- Object staticValue = staticMethod.invoke(instance, new String[]{});
- // staticValue = staticMethod.invoke(null, new String[]{});
- System.out.println(staticValue);
- }
- }
访问成员变量
设置成员变量值 .通过Class对象的的getField()方法可以获取该类所包含的全部或指定的成员变量Field,Filed提供了如下两组方法来读取和
- getXxx(Object obj): 获取obj对象的该成员变量的值, 此处的Xxx对应8中基本类型,如果该成员变量的类型是引用类型, 则取消get后面的Xxx;
- setXxx(Object obj, Xxx val): 将obj对象的该成员变量值设置成val值.此处的Xxx对应8种基本类型, 如果该成员类型是引用类型, 则取消set后面的Xxx;
- package com.lwl.reflect;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通过反射,对类中的字段进行操作
- * @create 2017-10-11 上午11:45:20
- * @version 1.0
- */
- public class ReflectFieldDemo {
- public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
- //获取类对象
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- //获取对象
- Object instance = clazz.newInstance();
- // instance = clazz.getDeclaredConstructor(null).newInstance(null);
- //根据属性的名称 获取属性对象
- Field field = clazz.getDeclaredField("name");
- //获取属性的类型
- Class<?> type = field.getType();
- System.out.println(type); //out print class java.lang.String
- //获取属性的名称
- String name = field.getName();
- System.out.println(name); //out print name
- //由于name属性是private,如果不设置setAccessible是无法直接对其进行设置
- //setAccessible是暴力破坏,如果是私有方法同理要设置
- field.setAccessible(true);
- field.set(instance, "张三");
- System.out.println(instance.toString()); //out print Person [id=null, name=张三, address=null]
- }
- }
通过反射赋值
- package com.lwl.reflect;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * 通过反射,对类对象进行赋值操作
- * @create 2017-10-11 上午11:44:58
- * @version 1.0
- */
- public class ReflectSetValueDemo {
- /**
- * 用一句话说明这个方法做什么
- * @param args
- * @throws ClassNotFoundException
- * @throws SecurityException
- * @throws NoSuchFieldException
- * @throws NoSuchMethodException
- * @throws InvocationTargetException
- * @throws IllegalArgumentException
- * @throws IllegalAccessException
- * @throws InstantiationException
- * @create 2017-10-11 上午9:41:51
- */
- public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
- //获取类的Class的三种方式
- /*
- * 1. Class.forName(类名称全称:包括包名)
- * 2. 类.class 即:Person.class
- * 3. 对象.getClass() new Person().getClass();
- * */
- Class<?> clazz = Class.forName("com.lwl.reflect.Person");
- // clazz = new Person().getClass();
- // clazz = Person.class;
- //获取一个属性
- Field field = clazz.getDeclaredField("address");
- System.out.println(field.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是对方法进行操作--------------------------------------------------------");
- //获取一个方法
- Method method = clazz.getDeclaredMethod("getName", new Class[]{});
- //传递的Class<?>的顺序要和方法的参数类型顺序保持一致,不然就无法匹配抛出异常:java.lang.NoSuchMethodException
- Method method1 = clazz.getDeclaredMethod("setName", String.class);
- //获取方法的名字
- // String name = method1.getName();
- Method method2 = clazz.getDeclaredMethod("setInfo", String.class,Integer.class);
- //method1 与 method2 还可以使用另外一种方式获取
- Method method3 = clazz.getDeclaredMethod("setName", new Class[]{String.class});
- Method method4 = clazz.getDeclaredMethod("setInfo", new Class[]{String.class,Integer.class});
- System.out.println(method.toString());
- System.out.println(method1.toString());
- System.out.println(method2.toString());
- System.out.println(method3.toString());
- System.out.println(method4.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是对构造器进行操作--------------------------------------------------------");
- //因为默认构造器没有参数,使用可以传入null 或者 new Class[]{}
- Constructor<?> cs = clazz.getDeclaredConstructor(new Class[]{});
- //带参数的构造器
- Constructor<?> cs2 = clazz.getDeclaredConstructor(new Class[]{Integer.class,String.class,String.class});
- System.out.println(cs.toString());
- System.out.println(cs2.toString());
- System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作--------------------------------------------------------");
- //根据类的默认构造器 创建一个类对象
- Object object = cs.newInstance(new Object[]{});
- // object = cs.newInstance(null);
- //根据类的带参数构造器,创建一个类对象
- Object object2 = cs2.newInstance(new Object[]{1,"李四","南京"});
- // object2 = cs2.newInstance(null);
- System.out.println("原始的对象属性情况:"+object);
- System.out.println("原始的对象属性情况:"+object2);
- System.out.println("--------------------------------------------我是分隔符:以下是对反射赋值进行操作:设置开始--------------------------------------------------------");
- //对属性进行设置值,先获取所有的方法
- Method[] methods = clazz.getDeclaredMethods();
- //获取类的所有属性
- Field[] fields = clazz.getDeclaredFields();
- for (Method m : methods) {
- //获取方法的名称
- String name = m.getName();
- //如果名称是以set开头的,表示设置值
- if(name.startsWith("set")){
- //获取set之后的字符串,即属性的名称
- String fieldName = name.substring(3);
- //因为set之后的首个字符串是大写,所以要截取第一个字符串转化为小写,这里千万别把所有的字符串都转化为小写,防止出现UserName 被转化为username
- fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
- //这里会对类中的属性进行赋值
- //由于Person里面一个特殊的setInfo的方法,且info不是类的属性,则不会进行赋值
- setFieldValue(fieldName, fields, m, object);
- }
- }
- System.out.println("赋值后的对象属性情况:"+object);
- System.out.println("赋值后的对象属性情况:"+object2);
- }
- /**
- * 给类属性赋值
- * @param fieldName
- * @param fields
- * @param m
- * @param object
- * @throws IllegalAccessException
- * @throws IllegalArgumentException
- * @throws InvocationTargetException
- * @create 2017-10-11 上午10:41:53
- */
- public static void setFieldValue(String fieldName, Field[] fields, Method m, Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
- for (Field field : fields) {
- if (field.getName().equals(fieldName)){
- //获取字段的属性
- Class<?> fieldClass = field.getType();
- //如果是Integer 即知道这个是Person的ID
- if(fieldClass == Integer.class){
- //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
- m.invoke(object, new Integer[]{1});
- }
- //因为同为String的有2个set方法,所有要通过属性名称判断到底是调用哪个
- else if (fieldClass == String.class && "name".equals(fieldName)){
- //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
- m.invoke(object, new String[]{"jack"});
- }
- else if (fieldClass == String.class && "address".equals(fieldName)){
- //通过反射设置值:也就是通过object对象,调用当前的 m 方法,后面是 m 方法需要的参数
- m.invoke(object, new String[]{"南京"});
- }
- //不需要再次循环
- return;
- }
- }
- }
- }
使用到的辅助类:
- package com.lwl.reflect;
- public class Person {
- private Integer id;
- private String name;
- private String address;
- public Person() {
- }
- public Person(Integer id, String name, String address) {
- this.id = id;
- this.name = name;
- this.address = address;
- }
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getAddress() {
- return address;
- }
- public void setAddress(String address) {
- this.address = address;
- }
- public void setInfo(String name,Integer id){
- this.id = id;
- this.name = name;
- }
- public static void printInfo(){
- System.out.println("我是静态方法,我被调用了");
- }
- @Override
- public String toString() {
- return "Person [id=" + id + ", name=" + name + ", address=" + address
- + "]";
- }
- }