一 . Java 的反射原理
Java的反射机制
二 .得到Class类实例对象的三种方式

1.根据原理图可以看出,要想通过反射得到某个类中的所有内容,就得要先得到这个类对应的Class类实例对象
2. 三种方式: ① ____(类名).class; ② __(对象名).getClass(); ③ Class.forName(“类的路径”)
3. 示例: 首先先写一个Person类,作为之后要得到内容的类

package com.lzw.reforce;
public class Person {
    // 属性
	private String name;
	private int id;
	// 无参的构造方法
	public Person() {}
	// 有参数的构造方法
	public Person(String name,int id) {
		this.name=name;
		this.id=id;
	}
	// 普通方法
	public String getName() {return name;}
	public int getId() {return id;}
	public void setName(String name) {
		this.name = name;
	}
	public void setId(int id) {
		 this.id = id;
	}
	
	public String toString() {
		return name+" "+id;
	}
	
	public static void print(String s) {
		System.out.println(s);
	}
}`

三种不同的得到Class实例对象的方式:

        // 得到Class类对象的三种方式
		// 1. __(类名).class;
		// Class<Person> c2 = Person.class;
		// 2. ___(对象名).getClass();
		// Class c3 = new Person().getClass();
		// 3. Class.forName(包括包名的类路径)
		Class c = Class.forName("com.lzw.reforce.Person");

△ 注意:第三种方式中类路径是包括包名的(可以利用双击类名 — 右键 ---- Copy Qualified Name 快速得到)

  1. 很明显,在类中存在三部分内容,属性,构造方法以及其他的普通方法,分别对应了三个类。 属性 ----- Field 类 , 构造方法 ---- Constructor类 , 普通方法 ----- Method类

三.通过反射操作构造方法创建实例对象
1. 通过无参数的构造方法创建实例对象

        Person p = (Person)c.newInstance();  // 直接通过Class类的newInstance方法创建实例对象
		p.setName("小明");
		p.setId(13);
		System.out.println(p.getName()+" "+p.getId());     // 小明 13

2.通过有参数的构造方法创建实例对象

  • 通过Class类的getConstructor方法得到该构造方法的对象
  • 该方法传递的参数是要得到的构造方法的参数类型,以class形式传递
  • 之后通过Constructor类的newInstance方法创建实例对象,参数就是构方的参数
        Constructor con = c.getConstructor(String.class,int.class);
		Person p2 = (Person)con.newInstance("小红",15);
		System.out.println(p2.getName()+" "+p2.getId());    // 小红 15

四. 通过反射操作属性

  • 通过Class类的getDeclaredField可得到该属性对应的Field类对象,参数为属性名
  • Field 类对象有两个常用方法:get(Object obj) 和 set(Object obj, Object value)
  • get方法的参数是要调用该属性的所属实例对象
  • set方法的第一个参数是要设置属性的实例对象,第二个参数是设置的属性值
  • setAccessible()方法设置是否允许设置或修改私有属性的值,默认是不允许
        Field name = c.getDeclaredField("name");     // 获得name属性对应的Field类对象
		Field id = c.getDeclaredField("id");      // 获得id属性对应的Field类对象
		name.setAccessible(true);     // 使反射可以操作私有属性
		name.set(p2, "小江");
		id.setAccessible(true);
		id.set(p2, 10);
		System.out.println(name.get(p2)+" "+id.get(p2));     // 小江 10
		System.out.println(p2.getName()+" "+p2.getId());      // 小江 10

五.通过反射操作普通方法(若方法是私有方法,也要先调用setAccessible方法进行设置)
1. 调用非静态无参数的普通方法

  • 通过Class类的getDeclaredMethod方法得到该普通方法对应的Method类对象,参数是方法名
  • 通过Method类的invoke方法调用该方法,参数是调用该方法的实例对象
        Method m = c.getDeclaredMethod("toString");
		System.out.println(m.invoke(p));         //  小明 13
		System.out.println(m.invoke(p2));       // 小江 10

2.调用非静态的有参数的普通方法

  • 通过Class类的getDeclaredMethod方法得到该普通方法对应的Method类对象,第一个参数是该方法的名称,第二个参数是该方法中的参数类型,以class形式传递
  • 通过Method类的invoke方法调用该方法,第一个参数是调用该方法的实例对象,第二个参数是该方法所需传的参数
        Method set_name = c.getDeclaredMethod("setName",String.class);
		set_name.invoke(p,"李华");
		System.out.println(p.getName());      // 李华

3.调用静态方法

  • 非静态方法的调用是 : 实例对象 . 方法名(参数),而静态方法的调用是 类名 . 方法名(参数),所以静态方法的调用不需要用到实例对象,所以在invoke方法中本应该传实例对象的参数改为null即可。
        Method print = c.getDeclaredMethod("print",String.class);
		print.invoke(null,"hello world");     // hello world

相关文章: