一、基本引言。
(1)基本内容回顾。
- 上篇博客的学习《Class类对象的三种实例化方式及使用时机、利用"反射"获取构造方法及详细信息——>Constructor类相关操作》Java反射学习(2)(“反射“机制获取构造方法及内部信息(Constructor类))-CSDN博客
(2)本篇博客的核心内容-基本介绍。
- 本篇博客的内容围绕:通过"反射"机制(.class字节码文件——>Class类对象)获取成员变量及详细信息——>Field类的相关操作。
- 原理图如下所示。
二、Java中使用"反射"机制获取成员变量及内部的详细信息。
(1)"反射"机制获取成员变量及详细信息的基本概念。
- 在Java中,反射是一种强大的机制,它允许程序在运行时访问、检查和修改它自己的结构,比如类、接口、字段和方法。合理使用"反射"特性,可以获取成员变量(字段)及其详细信息。
- 在介绍如何使用"反射"来获取类中(.class字节码文件)的成员变量及其详细信息的基本步骤之前需要先了解类"Field"。
(2)利用Java的对象机制进行封装。(Field类)
- 基于"Java万事万物皆对象"的机制。
- 使用.class(字节码文件)——(字节码文件对象)"Class"类对象获取对应类的信息。
1、构造方法。(Constructor类)
- 封装构造方法的实体类"Constructor"。(在引言中已经提及)
2、字段(成员变量)。(Field类)
- 封装成员变量的实体类"Field"。(本篇博客讨论的重点)
3、成员方法。(Method类)
- 封装成员方法的实体类"Method"。(后面博客讨论学习)
(3)操作成员变量(字段)的类"Field"相关的操作方法。
1、Class类中用于获取成员变量(字段)(返回Field类对象)的常用方法。
- 简单识别法:带"s"的获取的值不只一个。带"declared"无视访问修饰符权限全部拿到。
方法声明 功能描述 Field [] getFields(); 返回所有公共成员变量对象的数组。 Field [] getDeclaredFields(); 返回所有成员变量对象的数组。(包括私有成员变量) Field getField(String name); 返回单个公共成员变量对象。
(获取到成员变量对象:进行"解剖"——>获取权限修饰符、数据类型、存储的值都能够获取到!)
Field getDeclaredField(Stringname); 返回单个成员变量对象。 2、Field类中用于创建对象的方法。
方法声明 功能描述 void set(Object obj,Object value); 给成员变量(字段)赋值。 Object get(Object obj); 获取成员变量(字段)的值。 3、Field类对象的重要且常用的操作方法。
方法声明 功能描述 getModifiers(); 获取属性的权限修饰符。 getName(); 获取属性的名称。 isAccessible(); 判断属性是否可被外部访问。 setAccessible(Boolean flag); 设置属性是否可被外部访问。 toString(); 返回Field类的信息。 (4)有关"Field"类的核心方法的操作演示。
- 提供一个实体类:Student。
- Student类提供三个成员变量。提供正常的构造方法、getter与setter方法。
- 访问权限为private的成员变量name。
- 访问权限为private的成员变量age。
- 访问权限为public的成员变量gender。
package com.fs.entity; public class Student { //提供成员变量 private String name; private int age; public String gender; //无参构造(访问权限:public) public Student() { } //有参构造(访问权限:public) public Student(String name, int age, String gender) { = name; this.age = age; this.gender = gender; } //提供对于成员属性的getter、setter方法 public String getName() { return name; } public void setName(String 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; } //提供toString方法 @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + ", gender='" + gender + '\'' + '}'; } }
- 最后会提供一个测试类(Main类)进行核心方法操作的测试。
<1>第一步。获取对应Student类的字节码文件对象(Class类)。
package com.fs.test; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); } }
<2>第二步。通过Class对象获取Student类中对应成员变量(字段)"Field"对象。
- 通过字节码文件对象(Class对象)获取所有公共的(public)成员变量。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; public class Main { public static void main(String[] args) throws ClassNotFoundException{ //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //通过字节码文件对象获取所有公共(public)的成员变量对象 Field[] fields = clazz.getFields(); for (Field field : fields) { System.out.println(field); } } }
通过字节码文件对象(Class对象)获取所有成员变量。(包括private修饰的字段)
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException{ //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //通过字节码文件对象获取所有的成员变量对象 Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { System.out.println(field); } } }
- 获取单个成员变量。(public修饰的)
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(public gender)对象 Field gender = clazz.getField("gender"); System.out.println(gender); } }
- 获取单个成员变量。(private修饰的)
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field name = clazz.getDeclaredField("name"); System.out.println(name); } }
<3>第三步。通过获取的成员变量(字段)"Field"对象获取其内部详细信息。
- 获取成员变量的访问权限修饰符。
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field name = clazz.getDeclaredField("name"); System.out.println(name); //获取成员变量的访问修饰符 int modifiers = name.getModifiers(); System.out.println(modifiers); } }
- 获取成员变量的对应名称。
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field nameField = clazz.getDeclaredField("name"); System.out.println(nameField); //获取成员变量的名称 String name = nameField.getName(); System.out.println(name); } }
- 获取成员变量的对应参数数据类型。
package com.fs.test; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field nameField = clazz.getDeclaredField("name"); System.out.println(nameField); //获取成员变量的参数的数据类型 Class<?> type = nameField.getType(); System.out.println(type); } }
- 获取对应成员变量对象的值。
- 前提得创建(拥有)一个Student类的对象。
- 调用“Field”类对象的get()方法。传入值:Student类的对象即可。
- 通过方法setAccessible(Boolean flag)"强行关闭权限校验"拿取对应的属性值。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field nameField = clazz.getDeclaredField("name"); System.out.println(nameField); //获取成员变量对应的值 //前提:从创建的对象中获取成员变量的值 //创建一个Student类对象 Student s = new Student("张三", 23, "男"); //临时取消访问权限检查 nameField.setAccessible(true); //获取对应的name属性值 String value = (String) nameField.get(s); System.out.println(value); } }
- 修改成员变量(字段)对象里面存储的值。
- 使用set(Objetc obj,Object Value)方法即可。
package com.fs.test; import com.fs.entity.Student; import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { //1.通过Student类的全限定类名获取class字节码文件对象 Class<?> clazz = Class.forName("com.fs.entity.Student"); //获取单个成员变量(private name)对象 Field nameField = clazz.getDeclaredField("name"); System.out.println(nameField); //获取成员变量对应的值 //前提:从创建的对象中获取成员变量的值 //创建一个Student类对象 Student s = new Student("张三", 23, "男"); //临时取消访问权限检查 nameField.setAccessible(true); //获取对应的name属性值 String value = (String) nameField.get(s); System.out.println(value); //修改字段对象(Field)的指定字段值 //第一个参数:需要修改的对象,第二个参数:需修改的值 nameField.set(s, "李四"); System.out.println(s); } }