一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的,并且能够获得此类的引用。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。
反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。这时候,我们使用 JDK 提供的反射 API 进行反射调用。反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。是Java被视为动态语言的关键。
Java反射机制主要提供了以下功能:
①在运行时构造任意一个类的对象
②在运行时获取或者修改任意一个类所具有的成员变量和方法
③在运行时调用任意一个对象的方法(属性)
反射始于Class,Class是一个类,封装了当前对象所对应的类的信息。
一个类中有属性,方法,构造器等,比如说 有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述类,这就是 Class,它应该有类名,属性,方法,构造器等。Class是用来描述类的类。
Class类是一个对象照镜子的结果,对象可以看到自己有哪些属性,方法,构造器,实现了哪些接口等等。对于每 个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个类的有关信息。 对象只 能由系统建立对象,一个类(而不是一个对象)在 JVM 中只会有一个Class实例。
获取Class对象的三种方式
①. 通过类名获取 类名.class
②. 通过对象获取 对象名.getClass()
③. 通过全类名获取 Class.forName(全类名) classLoader.loadClass(全类名)
例如获取People的Class对象:
- public class People {
-
- private String name;
-
- private int age;
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public int getAge() {
- return age;
- }
- }
通过三种方式获取:
- //方式一 通过类名获取 类名.class
- Class
peopleClass = People.class; -
- //方式二 通过对象获取 对象名.getClass()
- People people =new People();
- Class extends People> peopleClass1 = people.getClass();
-
- //方式三 通过全类名获取 Class.forName(全类名) classLoader.loadClass(全类名)
- try {
- Class> peopleClass2 = Class.forName("com.yuanzhen.People");
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e);
- }
方式一需要导入类的包,依赖太强,不导包就抛编译错误
方式二一般可以创建对象就不需要反射了
方式三最常用,没有依赖性
- //peopleClass 是否为People.class的实例
- boolean assignableFrom = peopleClass.isAssignableFrom(People.class);
通过反射来生成对象主要有两种方式:
①使用Class对象的newInstance()方法来创建Class对象对应类的实例。
②先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这 种方法可以用指定的构造器构造类的实例。
例如:
- //方式一 使用Class对象的newInstance()方法来创建Class对象对应类的实例
- try {
- People people1 = peopleClass.newInstance();
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (InstantiationException e) {
- throw new RuntimeException(e);
- }
- //方式二 先通过Class对象获取指定的Constructor对象
- //再调用Constructor对象的newInstance()方法来创建实例
- //这种方法可以用指定的构造器构造类的实例
- Constructor
constructor = null; - try {
- constructor = peopleClass.getConstructor(People.class);
- constructor.newInstance();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
上面提到了通过构造器可以创建对象,那么怎么获得构造器呢?
获得构造器的api:
| Constructor getConstructor(Class[] params) | 获得使用特殊的参数类型的public构造函数(包括父类) |
| Constructor[] getConstructors() | 获得类的所有公共构造函数 |
| Constructor getDeclaredConstructor(Class[] params) | 获得使用特定参数类型的构造函数(包括私有) |
| Constructor[] getDeclaredConstructors() | 获得类的所有构造函数(与接入级别无关) |
例如:
- public class People {
-
- public People(String name, int age) {
- this.name = name;
- this.age = age;
- }
- private People() {
-
- }
- public People(String name) {
- this.name = name;
- }
- }
- try {
- //获取Class对象
- Class> peopleClass = Class.forName("com.yuanzhen.People");
- //获得使用特殊的参数类型的public构造函数(包括父类)
- Constructor> constructor = peopleClass.getConstructor(String.class, int.class);
- //获得使用特定参数类型的构造函数(包括私有)
- constructor = peopleClass.getDeclaredConstructor();
- //获得类的所有公共构造函数
- Constructor>[] constructors = peopleClass.getConstructors();
- //获得类的所有构造函数(与接入级别无关)
- constructors = peopleClass.getDeclaredConstructors();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
获取类的成员变量的api:
| Field getField(String name) | 获得命名的公共字段 |
| Field[] getFields() | 获得类的所有公共字段 |
| Field getDeclaredField(String name) | 获得类声明的命名的字段 |
| Field[] getDeclaredFields() | 获得类声明的所有字段 |
例如:
- public class People {
-
- public String name;
-
- private int age;
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public int getAge() {
- return age;
- }
- }
- try {
- //获取Class对象
- Class> peopleClass = Class.forName("com.yuanzhen.People");
- //获得命名的公共字段 name
- Field field = peopleClass.getField("name");
- //获得类声明的命名的字段(包括私有) age
- Field field1 = peopleClass.getDeclaredField("age");
- //获得类的所有公共字段
- Field[] fields = peopleClass.getFields();
- //获得类声明的所有字段
- Field[] fields1 = peopleClass.getDeclaredFields();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
将成员变量赋值:
- try {
- //获取Class对象
- Class> peopleClass = Class.forName("com.yuanzhen.People");
- //获得命名的公共字段 name
- Field field = peopleClass.getField("name");
- //获得类声明的命名的字段(包括私有) age
- Field field1 = peopleClass.getDeclaredField("age");
- //创建对象
- Object people = peopleClass.newInstance();
- //暴力反射,解除私有限定
- field1.setAccessible(true);
- //将年龄设为20
- field1.set(people,20);
- //将姓名设为张三
- field.set(people,"张三");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
获取方法信息的api:
| Method getMethod(String name, Class[] params) | 使用特定的参数类型,获得命名的公共方法 |
| Method[] getMethods() | 获得类的所有公共方法 |
| Method getDeclaredMethod(String name, Class[] params) | 使用特写的参数类型,获得类声明的命名的方法 |
| Method[] getDeclaredMethods() | 获得类声明的所有方法 |
例如:
- public class People {
-
- public String name;
-
- private int age;
-
- private void setName(String name) {
- this.name = name;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- private String getName() {
- return name;
- }
-
- public int getAge() {
- return age;
- }
- }
- try {
- //获取Class对象
- Class> peopleClass = Class.forName("com.yuanzhen.People");
- //使用特定的参数类型,获得命名的公共方法
- Method method = peopleClass.getMethod("setAge", int.class);
- //使用特写的参数类型,获得类声明的命名的方法(包括私有)
- Method method1 = peopleClass.getDeclaredMethod("setName", String.class);
- //获得类的所有公共方法
- Method[] methods = peopleClass.getMethods();
- //获得类声明的所有方法(包括私有)
- Method[] methods1 = peopleClass.getDeclaredMethods();
-
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- try {
- //获取Class对象
- Class> peopleClass = Class.forName("com.yuanzhen.People");
- //使用特定的参数类型,获得命名的公共方法
- Method method = peopleClass.getMethod("setAge", int.class);
- //使用特写的参数类型,获得类声明的命名的方法(包括私有)
- Method method1 = peopleClass.getDeclaredMethod("setName", String.class);
- //创建对象实例
- Object people = peopleClass.newInstance();
- //暴力反射,解除私有限定
- method.setAccessible(true);
- //调用方法setAge
- method.invoke(people,20);
- //调用方法 setName
- method1.invoke(people,"张三");
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
反射的常规使用就是这些,本文主要是对常用反射api的记录总结。