什么是反射

反射是框架设计的灵魂。可用来获取任意类的名称,成员属性和方法等,并且还能改变对象数学,也可以调用其方法。

反射的好处

1)可以在程序运行过程中,操作这些对象
2)可以降低代码耦合度,提高程序可扩展性

利用反射获取Class对象

共有三种获取Class对象的方式
1、Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2、 类名.class:通过类名的属性class获取
多用于参数的传递
3、对象.getClass():getClass()方法在Object类中定义着。
多用于对象的获取字节码的方式
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

代码演示:

public class Person{
	public String name;
	private String password;
	public int age=18;
	protected int number;
	
	public Person(){ 
		password="000000";
	} 
	public Person(String name,int number) {
		this.name=name;
		this.number=number;
	}
	
	public void text1(){
		System.out.println("text1");
	}
	private void text2(int a){
		System.out.println("text2");
	}
}

用三种不同方式来获取Person的Class对象

//Class.forName("全类名")
Class getPerson = Class.forName("day01.Person");
// 类名.class
Class getPerson = Person.class;
//对象.getClass()
Class getPersson = new Person().getClass();

//获取Person类的全类名
String nameClass = getPerson.getName();

获取到class对象后,我们可以通过该对象获取到该类中的属性和方法

获取成员变量

Field[] getFields() :获取所有public修饰的成员变量
Field getField(String name) : 获取指定名称的 public修饰的成员变量
Field[] getDeclaredFields() : 获取所有的成员变量,不考虑修饰符
Field getDeclaredField(String name) :获取指定名称的成员变量
Field setAccessible(true) :暴力反射,忽略安全检查

Field[] fields = getPerson.getFields();
//该方法返回的是一个数组,可以该数字进行遍历可看到获取的成员变量
for (Field field : fields) {
	System.out.println(field);
}
/*
public java.lang.String web.Person.name
public int web.Person.age
从遍历的结果中我们可以看到该方法只获取到了由Public修饰的成员
*/
//获取成员名为 age 的成员变量
Field age = getPerson.getField("age");

//获取所有成员变量
Field[] field2 = get.getDeclaredFields();
for (Field declaredField : field2) {
	System.out.println(declaredField);
}
/*
public java.lang.String web.Person.name
private java.lang.String web.Person.password
public int web.Person.age
protected int web.Person.number
我们可以看到,该方法获取到的是所有的成员变量
*/

Field password = getPerson.getDeclaredField("password");

//可以通过暴力反射来获取password中的值
password.setAccessible(true);
System.out.println(password.get(new Person())); //结果为 000000

获取构造方法

Constructor[] getConstructors() : 获取所有public修饰的构造方法方法
Constructor getConstructor(参数类型.class) :获取指定参数类型的构造方法
Constructor getDeclaredConstructor(参数类型.class) :获取指定参数类型构造方法,不考虑修饰符
Constructor[] getDeclaredConstructors() :获取所有构造方法,不考虑修饰符

//使用方法和上面类似
Constructor[] con=getPerson.getConstructors();
for (Constructor constructor : con) {
	System.out.println(constructor);
}
/*遍历结果:
public web.Person()
public web.Person(java.lang.String,int)
*/
//获取指定参数类型构造方法:
Constructor constructor=getPerson.getConstructor(String.class,int.class);  // public web.Person(java.lang.String,int)

获取成员方法

Method[] getMethods() :获取所有public修饰的方法
Method getMethod(参数类型.class) :获取指定参数的方法(可用来区分重载方法)
Method[] getDeclaredMethods() :获取所有方法,不考虑修饰符
Method getDeclaredMethod(参数类型.class) :获取指定参数方法,不考虑修饰符
invoke(对象,参数) :执行获取到的方法

//使用方法同上,这里挑两个进行演示、
//获取所有public修饰的方法
Method[] all=getPerson.getMethods();
for (Method method : all) {
	System.out.println(method);
}
/*返回结果除了已有的public修饰的方法,还有包括继承父类的方法
public void web.Person.text1()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
*/

Method text2=getPerson.getDeclaredMethod("text2",int.class);
//可通过暴力反射来执行此方法
text2.setAccessible(true);
text2.invoke(new Person(),1);  //注意这里需要进行传参,因为text2方法本身就需要传参才能正确执行