反射的定义
定义:反射就是对封装类的字段,方法和构造函数的所有信息进行编程访问的一种手段。
(Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任
意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信
息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。)
一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象 来提供给用户进行操作。
相关知识
Class对象
在java世界里,一切皆对象。从某种意义上来说,java有两种对象:实例对象和Class对象。每个类的运行时的类型信息就是用Class对象表示的。它包含了与类有关的信息。其实我们的实例对象就通过Class对象来创建的。(这个类Class对象只有一个,这个类的所有实例对象都通过对象头指向这个Class对象)
(Class类被创建后的对象就是Class对象,这里需要注意,Class对象表示的是自己手动编写类的类型信息。)
具体过程如下
各种信息对象
反射的使用
步骤:
获取Class对象
将Class对象里的信息对象解剖出来
调用
准备一个类用来做例子:
package 反射.myreflect1;
public class Student {
public String name = "66"; // 公有字段,存储学生的姓名,初始值为 "66"
protected int age = 11; // 受保护字段,存储学生的年龄,初始值为 11
private String sex = "男"; // 私有字段,存储学生的性别,初始值为 "男"
// 默认构造方法
public Student() {
System.out.println("调用了无参构造");
}
// 使用指定的姓名初始化
public Student(String name) {
this.name = name;
System.out.println("调用了一个参数的构造");
}
// 使用指定的姓名和年龄初始化
protected Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("调用了两个参数的构造");
}
// 使用指定的姓名、年龄和性别初始化
private Student(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
System.out.println("调用了三个参数的构造");
}
// 公有方法,打印 "public"
public void Print1(String body) {
System.out.println("public"+body);
}
// 私有方法,打印 "private"
private void Print2(String body) {
System.out.println("private"+body);
}
// 受保护方法,打印 "protected"
protected void Print3(String body) {
System.out.println("protected"+body);
}
// 重写的 toString 方法,返回表示学生对象的字符串
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
}
获取Class对象的三种方式
第一种,使用 Class.forName("类的全路径名"); 静态方法。
前提:已明确类的全路径名。
第二种,使用 .class 方法。
说明:仅适合在编译前就已经明确要操作的 Class
第三种,使用类对象的 getClass() 方法
例子:
获取对象的代码演示
public class MyReflectDemo1 {
/*
* 获取class对象的三种方式:
* 1. Class.forName("全类名");
* 2. 类名.class
* 3. 对象.getClass();
*
* */
public static void main(String[] args) throws ClassNotFoundException {
//1. 第一种方式
//全类名 : 包名 + 类名
//最为常用的
Class clazz1 = Class.forName("反射.myreflect1.Student");
//2. 第二种方式
//一般更多的是当做参数进行传递
Class clazz2 = Student.class;
//3.第三种方式
//当我们已经有了这个类的对象时,才可以使用。
Student s = new Student();
Class clazz3 = s.getClass();
//说明我们通过不同的方式获取到的都是同一个Class对象
System.out.println(clazz1.equals(clazz2));
System.out.println(clazz2.equals(clazz3));
说明实例对象都是公用一个Class对象的
System.out.println("说明实例对象都是公用一个Class对象的----------------------------------------");
Student s1 = new Student();
Student s2 = new Student();
Class clazz11 = s1.getClass();
Class clazz22 = s2.getClass();
System.out.println(clazz11.equals(clazz22));
}
}
结果:
说明我们通过不同的方式获取到的都是同一个Class对象
通过反射获取构造方法并调用
package 反射.myreflect1;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;
public class MyReflectDemo {
/*
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 static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取class字节码文件对象
Class clazz = Class.forName("反射.myreflect1.Student");
System.out.println("获取公共构造方法对象---------------------------------------------------------");
Constructor[] cons1 = clazz.getConstructors();
for (Constructor con : cons1) {
System.out.println(con);
}
System.out.println();
System.out.println("获取全部构造方法对象(包括:私有、受保护、默认、公有)---------------------------------------------------------");
System.out.println();
Constructor[] cons2 = clazz.getDeclaredConstructors();
for (Constructor con : cons2) {
System.out.println(con);
}
System.out.println();
System.out.println("根据参数获取单个构造方法对象(包括:私有、受保护、默认、公有)---------------------------------------------------------");
Constructor con4 = clazz.getDeclaredConstructor(String.class,int.class,String.class);
System.out.println(con4);
//获取对应参数列表
Parameter[] parameters = con4.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
System.out.println();
System.out.println("创建实例---------------------------------------------------------");
//暴力反射:表示临时取消权限校验
con4.setAccessible(true);
//创建对象
反射.myreflect1.Student stu = (Student) con4.newInstance("张三",23,"男");
System.out.println(stu);
}
}
结果
通过反射获取成员变量并设置
package 反射.myreflect1;
import 反射.myreflect1.Student;
import java.lang.reflect.Field;
public class MyReflectDemo2 {
/*
Class类中用于获取成员变量的方法
Field[] getFields(): 返回所有公共成员变量对象的数组
Field[] getDeclaredFields(): 返回所有成员变量对象的数组
Field getField(String name): 返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象
Field类中用于赋值对象的方法
void set(Object obj, Object value):赋值
Object get(Object obj) 获取值
*/
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
//1.获取class字节码文件的对象
Class clazz = Class.forName("反射.myreflect1.Student");
//2.获取所有的成员变量
System.out.println();
System.out.println("获取所有的成员变量-----------------------------------------------------------");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
//获取单个的成员变量
System.out.println();
System.out.println("获取单个的成员变量-----------------------------------------------------------");
Field name = clazz.getDeclaredField("name");
System.out.println(name);
//获取成员变量的权限修饰符
System.out.println();
System.out.println("获取成员变量的权限修饰符-----------------------------------------------------------");
int modifiers = name.getModifiers();
System.out.println(modifiers);
//获取成员变量的名字
System.out.println();
System.out.println("获取成员变量的名字-----------------------------------------------------------");
String n = name.getName();
System.out.println(n);
//获取成员变量的数据类型
System.out.println();
System.out.println("获取成员变量的数据类型-----------------------------------------------------------");
Class<?> type = name.getType();
System.out.println(type);
//获取成员变量记录的值
System.out.println();
System.out.println("获取成员变量记录的值并修改----------------------------------------------------------");
反射.myreflect1.Student s = new Student("zhangsan");
name.setAccessible(true);
String value = (String) name.get(s);
System.out.println(value);
//修改对象里面记录的值
name.set(s, "lisi");
System.out.println(s);
}
}
结果:
获取成员方法并调用
package 反射.myreflect1;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class MyReflectDemo4 {
/*
Class类中用于获取成员方法的方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes) :返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象
Method类中用于创建对象的方法
Object invoke(Object obj, Object... args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)
获取方法的修饰符
获取方法的名字
获取方法的形参
获取方法的返回值
获取方法的抛出的异常
*/
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1. 获取class字节码文件对象
Class clazz = Class.forName("反射.myreflect1.Student");
//2. 获取里面所有的方法对象(包含父类中所有的公共方法)
System.out.println();
System.out.println("获取里面所有的方法对象-----------------------------------------------------------");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// 获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)
System.out.println();
System.out.println("获取里面所有的方法对象(不能获取父类的,但是可以获取本类中私有的方法)-----------------------------------------------------------");
Method[] methods1 = clazz.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method);
}
// 获取指定的单一方法
System.out.println();
System.out.println("获取指定的单一方法-----------------------------------------------------------");
Method m = clazz.getDeclaredMethod("Print2", String.class);
System.out.println(m);
// 获取方法的修饰符
System.out.println();
System.out.println("获取方法的修饰符-----------------------------------------------------------");
int modifiers = m.getModifiers();
System.out.println(modifiers);
// 获取方法的名字
System.out.println();
System.out.println("获取方法的名字-----------------------------------------------------------");
String name = m.getName();
System.out.println(name);
// 获取方法的形参
System.out.println();
System.out.println("获取方法的形参-----------------------------------------------------------");
Parameter[] parameters = m.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter);
}
//获取方法的抛出的异常
System.out.println();
System.out.println("获取方法的抛出的异常----------------------------------------------------------");
Class[] exceptionTypes = m.getExceptionTypes();
for (Class exceptionType : exceptionTypes) {
System.out.println(exceptionType);
}
//方法运行
/*Method类中用于创建对象的方法
Object invoke(Object obj, Object... args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)*/
System.out.println();
System.out.println("方法运行----------------------------------------------------------");
Student s = new Student();
m.setAccessible(true);
//参数一s:表示方法的调用者
//参数二"汉堡包":表示在调用方法的时候传递的实际参数
String result = (String) m.invoke(s,"你好");
System.out.println(result);
}
}
结果: