一、基本概念

1.反射机制:在运行状态中,可以动态的获取类信息及动态的调用类对象方法的功能。

2.反射常用的几个方法

(1)getDeclaredMethod(方法名,参数):返回对应的方法;

(2)Field属性:getType()返回字段类型,getName()返回字段名称,set()设置新值

3.反射的作用?

(1)在运行时判断任意一个对象所属的类、判断任意一个类所具有的成员变量和方法。

(2)在运行时构造任意一个类的对象;

(3)在运行时调用任意一个对象的方法。

4.反射的应用场景?

(1)Spring IOC的对象注入;

5.反射的性能?如何优化?

(1)反射性能比直接的java代码要慢,反射相当于一系列解释操作,通知jvm要做哪些事情。反射主要性能损耗是在对方法或变量的获取时。

二、反射应用

1.通过反射获取类的方法、属性、构造器

public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.根据一个类的全名字符串来获得一个类的对象
        Class<?> clazz=Class.forName("java.lang.String");
        //2.获得传递过来类的所有方法
        Method[] methods=clazz.getDeclaredMethods();
        //System.out.println(Arrays.toString(methods));
        for(Method m:methods){
            System.out.println(m);
        }
        System.out.println("--------------------");
        //3.获取类的所有属性
        Field[] fields=clazz.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("--------------------");
        //4.获取类的所有构造器
        Constructor[] constructors=clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
    }
}

2.通过反射获得class对象3种方式

Java理解反射 java反射详解_System

public class getClassThree {
    //1.知道类字符串
    public static void test1() throws ClassNotFoundException {
        //获得一个类的类对象
      Class<?> clazz=Class.forName("java.util.HashMap");

    }

    //2.知道是一个对象,但不知道是什么对象
    public static void test2(Object obj) {
        //获得一个类的类对象
        Class<?> clazz=obj.getClass();
        //2.获得传递过来类的所有方法
        Method[] methods=clazz.getDeclaredMethods();
        //System.out.println(Arrays.toString(methods));
        for(Method m:methods){
            System.out.println(m);
        }
        System.out.println("--------------------");
        //3.获取类的所有属性
        Field[] fields=clazz.getDeclaredFields();
        for (Field f : fields) {
            System.out.println(f);
        }
        System.out.println("--------------------");
        //4.获取类的所有构造器
        Constructor[] constructors=clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println(c);
        }

    }
    //3.知道类名
    public static void test3() {
        Class<?> clazz=Map.class;
        //获得类的所有方法
        Method[] methods=clazz.getDeclaredMethods();
        System.out.println(Arrays.toString(methods));
    }
}

3.通过反射调用方法(静态、非静态)、访问私有属性、私有方法,拷贝对象

(1)person测试类

package reflectTest;

public class Person {
	
	private Integer  id;
	
	private String name;
	
	private String address;
    /*构造函数*/
	public Person() {
	}
	
	public Person(Integer id, String name, String address) {
		super();
		this.id = id;
		this.name = name;
		this.address = address;
	}

	private static void printInfo(){
		System.out.println("静态方法的反射调用成功");
	}
	
	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;
	}

	@Override
	public String toString() {
		return "Person [id=" + id + ", name=" + name + ", address=" + address
				+ "]";
	}
}

(2)通过反射调用非静态方法、调用静态方法

//invoke():就是去调用方法

public class ReflectDemo1 {
    //调用非静态方法
    public static void main(String[] args) throws Exception {
        Class<?> class1 = Class.forName("reflectTest.Person");
        //获得构造器
        Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
        //根据类的默认构造器来获得一个对象
        Object instance = constructor.newInstance(new Object[]{});

        /*--------------调用非静态方法----------------- */
        System.out.println("调用非静态方法:");
        //获得method对象
        Method method1 = class1.getDeclaredMethod("setName", new Class[]{String.class});
        //执行对象的某个方法
        Object invoke = method1.invoke(instance, new Object[]{"张三"});
        System.out.println("调用非静态方法 setName():"+invoke);


        Method method2 = class1.getDeclaredMethod("getName", null);
        //Method mget = class1.getDeclaredMethod("getName", new Class[]{});
        Object invoke2 = method2.invoke(instance, new Object[]{});
        System.out.println("调用非静态方法 getName():"+invoke2);

        /*----------------调用静态方法--------------------*/
        System.out.println("-----------------------");
        System.out.println("调用静态方法:");
        Method method3 = class1.getDeclaredMethod("printInfo", null);
        //破坏私有方法,让我们能调用
        method3.setAccessible(true);
        Object invoke3 = method3.invoke(null, null);

    }

}

(3)通过反射访问私有属性、访问静态私有方法

//设置私有属性

public static void main(String[] args) throws Exception {
        Class<?> class1 = Class.forName("reflectTest.Person");
        //获得构造器
        Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
        //根据类的默认构造器来获得一个对象
        Object instance = constructor.newInstance(new Object[]{});

        //根据方法名字来获得属性对象
        Field field = class1.getDeclaredField("name");

        //破坏掉私有属性
        field.setAccessible(true);
        field.set(instance, "张三");

        //获得属性的类型
        Class<?> type = field.getType();
        System.out.println(type);
 }

//访问静态私有方法

System.out.println("调用静态方法:");
    Method method3 = class1.getDeclaredMethod("printInfo", null);
    //破坏私有方法,让我们能调用
    method3.setAccessible(true);
    Object invoke3 = method3.invoke(null, null);

(4)通过反射拷贝对象

public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        Class<?> class1 = Class.forName("reflectTest.Person");
        //获得构造器
        Constructor<?> constructor = class1.getDeclaredConstructor(new Class[]{});
        //根据类的默认构造器来获得一个对象
        Object instance = constructor.newInstance(new Object[]{});
        System.out.println(instance);

        //获得类的所有方法
        Method[] methods = class1.getDeclaredMethods();
        for(Method m :methods){
            //获得方法的名字
            String name = m.getName();
            //获得是否以set开始
            boolean startsWith = name.startsWith("set");
            if(startsWith){
                //获得到了set字符串的后面的值
                String fieldName = name.substring(3);
                //获得属性的名字
                fieldName = fieldName.substring(0, 1).toLowerCase()+fieldName.substring(1);
                //获得方法所对应的属性
                Field field = class1.getDeclaredField(fieldName);
                //获得属性的具体类型,获得属性对应的类型
                Class<?> type = field.getType();

                if(type == Integer.class){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{1});
                }
                if(type == String.class && "address".equals(fieldName)){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{"北京"});
                }
                if(type == String.class && "name".equals(fieldName)){
                    //反射调用set方法
                    m.invoke(instance, new Object[]{"张三"});
                }
            }
        }
        System.out.println(instance);
		/*Constructor<?> constructor1 = class1.getDeclaredConstructor(new Class[]{Integer.class, String.class, String.class});
		Object instance2 = constructor1.newInstance(new Object[]{1, "李四","北京"});
		System.out.println(instance2);*/
    }
}