反射
反射允许对成员变量、成员方法和构造方法的信息进行编程访问。简单来说就是获取类里所有的信息。IDEA里自动提示的功能就是通过反射实现的。
获取class对象的三种方式
1.Class.forName("全类名")
2.类名.class
3.对象.getclass()
这三种方式对应Java当中三个不同的阶段。如果我们想创建一个类对象,分为以下三个阶段:
1.编写.java文件,并将其编译为.class字节码文件。在这个阶段代码没有被加载到内存中,只是在硬盘上进行操作。这个阶段是源代码阶段。源代码阶段使用第一种方式获取class对象
2.接下来要运行代码。将.class字节码文件加载到内存当中。这个阶段是加载阶段。加载阶段使用第二种方式
3.我们可以在内存中new一个对象,这个阶段是运行阶段。运行阶段使用第三种方式。
public class ReflectionDemo1 {
public static void main(String[] args) throws ClassNotFoundException {
//1.第一种方式
//全类名:包名+类名,选中类名,右键找到复制/粘贴特殊,点击复制引用
//最为常用
Class Clazz1 = Class.forName("learn.reflection.Student");
//打印
System.out.println(Clazz1);
//2.第二种方式,一般更多的是当作参数进行传递
Class Clazz2 = Student.class;
//验证
System.out.println(Clazz1 == Clazz2);
//3.第三种方式
//当我们已经有了这个类的对象时才能使用
Student stu = new Student();
Class Clazz3 = stu.getClass();
//验证
System.out.println(Clazz1 == Clazz2);
System.out.println(Clazz2 == Clazz3);
}
}
利用反射获取构造方法
Class类中用于获取构造方法的方法:
| 方法名称 | 说明 |
|---|---|
| Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
| Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor<T>getConstructor(Class<?>...parameterTypes) | 返回单个公共构造方法对象 |
Constructor<T>getDeclaredConstructor(Class<?>...parameterTypes) | 返回单个构造方法对象 |
Constructor类中用于创建对象的方法
| 方法名称 | 说明 |
|---|---|
| T newInstance(Object...initargs) | 根据指定的构造方法创建对象 |
| setAccessible(boolean flag) | 设置为true,表示取消访问检查 |
新增几个构造函数:
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
protected Student(int age) {
this.age = age;
}
private Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class ReflectionDemo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取Student类的class字节码文件对象
Class clazz = Class.forName("learn.reflection.Student");
//2.获取public构造方法
Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("-------------");
//3.获取所有构造方法
Constructor[] dc = clazz.getDeclaredConstructors();
for (Constructor con : dc) {
System.out.println(con);
}
System.out.println("-------------");
//获取单个构造方法:空参构造
System.out.println(clazz.getDeclaredConstructor());
//获取单个构造方法:参数为一个String类型变量的构造函数
//括号中的参数与想要获得的构造方法的参数对应
System.out.println(clazz.getDeclaredConstructor(String.class));
//获取单个构造方法:参数为一个String类型和一个int类型变量的构造函数
Constructor TempCon = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(TempCon);
System.out.println("-------------");
//获取权限修饰符:.getModifiers方法
//public为1,private为2,protected为4
//static为8,final为16,synchronized为32
//用的都是2的n次幂
System.out.println(TempCon.getModifiers());
System.out.println("-------------");
//获取参数
Parameter[] parameters = TempCon.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
System.out.println("-------------");
//通过反射创建对象
//由于两个参数的构造方法为priavte
//要先临时取消权限校验
TempCon.setAccessible(true);
Student stu = (Student) TempCon.newInstance("张三",18);
System.out.println(stu);
}
}
利用反射获取成员变量
Class类中用于获取成员变量的方法
| 方法名称 | 说明 |
|---|---|
| Field[] getFields() | 返回所有公共成员变量对象的数组 |
| Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
| Field getField(String name) | 返回单个公共成员变量对象 |
| Field getDeclaredField(String name) | 返回单个成员变量对象 |
Field类中用于创建对象的方法
| 方法名称 | 说明 |
|---|---|
| void set(Object obj, Object value) | 赋值 |
| Object get(Object obj) | 获取值 |
修改Student类的内容:
public class Student {
private String name;
private int age;
public String gender;
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public Student() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + ''' +
", age=" + age +
", gender='" + gender + ''' +
'}';
}
}
public class ReflectionDemo1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//1.获取Student类的class字节码文件对象
Class clazz = Class.forName("learn.reflection.Student");
//2.获取public成员变量
Field[] fields1 = clazz.getFields();
for (Field field : fields1) {
System.out.println(field);
}
System.out.println("-------------");
//3.获取所有成员变量
Field[] fields2 = clazz.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
System.out.println("-------------");
//4.获取单个的成员变量
Field name = clazz.getDeclaredField("name");
System.out.println(name);
System.out.println("-------------");
//5.获取权限修饰符
System.out.println(name.getModifiers());
System.out.println("-------------");
//6.获取成员变量名
System.out.println(name.getName());
System.out.println("-------------");
//7.获取成员变量类型
System.out.println(name.getType());
System.out.println("-------------");
//8.获取成员变量记录的值
Student s = new Student("张三",18,"男");
name.setAccessible(true);
Object value = name.get(s);
System.out.println(value);
System.out.println("-------------");
//9.修改对象记录的值
name.set(s,"凯文");
System.out.println(s);
}
}
利用反射获取成员方法
方法名与前面类似,改成Method而已。
有几点需要注意:
1.getMethods方法可以获取所有public的方法对象,包括父类中所有的public方法。getDeclaredMethods则不能获取父类的,但可以获取私有的(和前面一样)
2.获取方法抛出的异常:
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
3.方法运行
Student s = new Student();
clazz.getMethod("eat", String.class).invoke(s,"汉堡");
invoke第一个参数表示方法的调用者,第二个参数表示在调用方法的时候传递的实际参数