当前位置: 首页 > news >正文

JavaSE笔记--反射篇

文章目录

    • 一、学习目标
    • 二、反射的概述
    • 三、反射的使用
      • 获取 class 对象的三种方式
      • 获取构造方法
      • 获取成员变量
      • 获取成员方法
    • 四、反射的作用(附综合练习)
      • 练习 1:保存对象数据
      • 练习 2:利用反射动态的创建对象和运行方法

一、学习目标

由于反射都是从 class 字节码文件中获取的内容,固任务有以下四点

  1. 学会如何获取 class 字节码文件的对象
  2. 利用反射如何获取构造方法(创建对象)
  3. 利用反射如何获取成员变量(赋值,即获值)
  4. 利用反射如何获取成员方法(运行)

请添加图片描述


二、反射的概述

  • 反射允许对成员变量,成员方法和构造方法的信息进行编程访问,
    理解:
  • 利用反射创建的对象可以无视修饰符调用类里面的内容
  • 可以跟配置文件结合起来使用,把要创建的对象信息和方法写在配置文件中。
    可以理解为把类的底裤扒的干干净净

三、反射的使用

获取 class 对象的三种方式

  1. 运用 Class 里面的静态方法 forName 获取
    运用场景:最常用
    语法: Class.forName("全类名")
  2. 通过 class 属性获取(这里以 Student 类为例)
    运用场景:一般当作参数进行传播
    语法:Student.class
  3. 通过对象获取字节码文件对象(这里以创建 Student 对象为 s 为例)
    运用场景:当有这个类的对象时才能使用
    语法:s.getClass()

以上三种方法适用于同一个类,获得字节码文件都是一样的。即在运行期间,一个类,只有一个Class对象产生

代码演示

public static void main(String[] args) throws ClassNotFoundException {  //1.第一种方式  Class clazz1 = Class.forName("Student");  //2.第二种方式  Class clazz2 =Student.class;  //3.第三种方式  Student s=new Student();  Class clazz3 =s.getClass();  System.out.println(clazz1 == clazz2);  //trueSystem.out.println(clazz3 == clazz2);  //true
}

获取构造方法

通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;
其中,获取构造方法主要基于 Constructor 类,直译为构造函数

用于获取构造方法的四个方法和两个创建对象的方法
(1)获取所有构造方法
Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组(包括私有、受保护的、默认、公有)

(2) 获取单个构造方法,可以在括号内加入对应的参数字节码文件,从而指定获取
Constructor getConstructor(Class<?> ... parameterTypes):返回指定公共构造方法对象
Constructor getDeclaredConstructors(Class<?> ... parameterTypes):返回指定构造方法对象(包括私有、受保护的、默认、公有)

(3) 用于创建对象的方法
newInstance (Object... initargs): 根据指定的构造方法创建对象
setAccessible(boolean flag): 设置为 true, 表示取消访问调查(暴力反射)

拓展:适用于构造方法、成员变量、成员方法

方法说明
int getModifiers获取构造方法的权限修饰符
int getParameterCount获取参数的个数
Class[] getParameterTypes获取参数的类型
Parameter[] getParameters获取所有参数
Student 类 (六种构造方法)
public class Student {  private String name;  private Integer age;  //---------------构造方法-------------------  //(默认的构造方法)  Student(String str){  System.out.println("(默认)的构造方法 s = " + str);  }  //无参构造方法  public Student(){  System.out.println("调用了公有、无参构造方法执行了。。。");  }  //有一个参数的构造方法  public Student(char name){  System.out.println("姓名:" + name);  }  //有多个参数的构造方法  public Student(String name ,int age){  System.out.println("姓名:"+name+"年龄:"+ age);//这的执行效率有问题,以后解决。  }  //受保护的构造方法  protected Student(boolean n){  System.out.println("受保护的构造方法 n = " + n);  }  //私有构造方法  private Student(int age){  System.out.println("私有的构造方法   年龄:"+ age);  }  }

测试类

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {  //1.获取class字节码文件对象  Class clazz = Class.forName("Student");  //获取构造方法  System.out.println("----------获取公共构造方法----------");  Constructor[] cos1=clazz.getConstructors();  for (Constructor constructor : cos1) {  System.out.println(constructor);  }  System.out.println("----------获取所有构造方法----------");  Constructor[] cos2= clazz.getDeclaredConstructors();  for (Constructor constructor : cos2) {  System.out.println(constructor);  }  System.out.println("----------获取单个公共构造方法----------");  Constructor constructor = clazz.getConstructor();       //获取无参构造  System.out.println(constructor);System.out.println("----------获取单个构造方法----------");  Constructor constructor1 = clazz.getDeclaredConstructor(String.class,int class);    //获取char构造  System.out.println(constructor1);  System.out.println("----------获取权限修饰符----------");  int mod=constructor1.getModifiers();  System.out.println(mod);  System.out.println("----------获取参数----------");  System.out.println("获取参数的个数");  int mod1=constructor1.getParameterCount();  System.out.println(mod1);  System.out.println("获取参数的类型");  Class[] parameterTypes = constructor1.getParameterTypes();  for (Class parameterType : parameterTypes) {  System.out.print(parameterType+"\t");  }  System.out.println("获取所有参数");  Parameter[] parameters = constructor1.getParameters();  for (Parameter parameter : parameters) {  System.out.print(parameter+"\t");  }System.out.println("----------创建对象----------");  Constructor con =clazz.getDeclaredConstructor(int.class);  //暴力反射:临时取消权限校验,使得可以访问如private的构造方法  con.setAccessible(true);  Student stu=(Student) con.newInstance(23);  System.out.println(stu);}

后台输出

----------获取公共构造方法----------
public Student(java.lang.String,int)
public Student(char)
public Student()
----------获取所有构造方法----------
private Student(int)
protected Student(boolean)
public Student(java.lang.String,int)
public Student(char)
public Student()
Student(java.lang.String)
----------获取单个公共构造方法----------
public Student()
----------获取单个构造方法----------
public Student(java.lang.String,int)
----------获取权限修饰符----------
1
----------获取参数----------
获取参数的个数
2
获取参数的类型
class java.lang.String	int	
获取所有参数
java.lang.String arg0	int arg1
----------创建对象----------
私有的构造方法   年龄:23
Student{name = null, age = null}	

以下是 API 中常量字段对应值
![[常量字段.png]]


获取成员变量

通过 Class 对象可以获取某个类中的:构造方法、成员变量、成员方法;
其中,获取成员变量主要基于 Field 类

用于获取成员变量的四个方法和两个创建对象的方法
(1) 获取所有成员变量
Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组

(2) 获取单个成员变量
Field getField(String name): 返回单个公共成员变量对象
Field getDeclaredField(String name): 返回单个成员变量对象

(3) 创建对象的方法
void set(Object obj,Object value): 赋值
Object get(Object obj): 获取值

Student 类

public class Student {  private String name;  private int age;  public String sex;  public Student() {  }  public Student(String name, int age, String sex) {  this.name = name;  this.age = age;  this.sex = sex;  }  public String toString() {  return "Student{name = " + name + ", age = " + age + ", sex = " + sex + "}";  }  
}

测试类

public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {  //1.获取class字节码文件的对象  Class clazz = Class.forName("Demo3.Student");  //2.获取成员变量  System.out.println("----------获取公共成员变量----------");  Field[] fields = clazz.getFields();  for (Field field : fields) {  System.out.println(field);  }  System.out.println("----------获取所有成员变量----------");  Field[] fields1=clazz.getDeclaredFields();  for (Field field : fields1) {  System.out.println(field);  }  System.out.println("----------获取单个公共成员变量----------");  Field field = clazz.getField("sex");  System.out.println(field);  System.out.println("----------获取单个成员变量----------");  Field field1 =clazz.getDeclaredField("name");  Field field2 =clazz.getDeclaredField("age");  System.out.println(field1);  System.out.println(field2);  System.out.println("----------获取成员变量的名字----------");  String name = field.getName();  System.out.println(name);  System.out.println("----------获取成员变量的数据类型----------");  Class type = field.getType();  System.out.println(type);  System.out.println("----------获取成员变量的值----------");  Student s=new Student("zhangsan",23,"男");  field.setAccessible(true);  Object o = field.get(s);  System.out.println(o);  System.out.println("----------修改成员变量的值----------");  System.out.println("修改前:"+s);  field.set(s,"女");  System.out.println("修改后:"+s);  
}

运行结果

----------获取公共成员变量----------
public java.lang.String Demo3.Student.sex
----------获取所有成员变量----------
private java.lang.String Demo3.Student.name
private int Demo3.Student.age
public java.lang.String Demo3.Student.sex
----------获取单个公共成员变量----------
public java.lang.String Demo3.Student.sex
----------获取单个成员变量----------
private java.lang.String Demo3.Student.name
private int Demo3.Student.age
----------获取成员变量的名字----------
sex
----------获取成员变量的数据类型----------
class java.lang.String
----------获取成员变量的值--------------------修改成员变量的值----------
修改前:Student{name = zhangsan, age = 23, sex =}
修改后:Student{name = zhangsan, age = 23, sex =}

获取成员方法

通过 Class 对象可以获取某个类中的:构造方法、成员变量、成员方法;
其中,获取成员方法主要基于 Method 类,直译为方法

用于获取成员方法的四个方法和一个创建对象的方法
(1) 获取所有成员方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括父类的公共方法
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括父类方法

(2) 获取单个成员方法
Method getMethod(String name, Class<?>... parameterTypes):返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes): 返回单个成员方法对象

(3) 创建对象方法
Object invoke(Object obj, Object... args) :运行方法

  • 参数一:用 obj 对象调用该方法
  • 参数二:调用方法的传递的参数(没有则不写)
  • 返回值:方法的返回值(如果没有就不写)

Student 类

public class Student {  private String name;  private int age;  public Student() {  }  public 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;  }  public void sleep(){  System.out.println("睡觉");  }  private String eat(String something) throws IOError, IOException{  System.out.println("在吃:"+something);  return "返回值测试";  }  public String toString() {  return "Student{name = " + name + ", age = " + age + "}";  }  
}

测试类

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {  //1.获取class字节码文件  Class clazz = Class.forName("Demo4.Student");  System.out.println("----------获取所有公共方法对象(包含父类中方法)----------");  Method[] methods = clazz.getMethods();  for (Method method : methods) {  System.out.println(method);  }  System.out.println("----------获取所有方法对象----------");  Method[] methods1 = clazz.getDeclaredMethods();  for (Method method : methods1) {  System.out.println(method);  }  System.out.println("----------获取单个公共方法对象----------");  Method m = clazz.getMethod("getAge");  System.out.println(m);  System.out.println("----------获取单个方法对象----------");  Method m1 = clazz.getDeclaredMethod("eat", String.class);  System.out.println(m1);  System.out.println("----------获取方法的修饰符----------");  int modifiers = m.getModifiers();  System.out.println(modifiers);  System.out.println("----------获取方法的名字----------");  String name = m.getName();  System.out.println(name);  System.out.println("----------获取方法的形参----------");  Parameter[] parameters = m1.getParameters();  for (Parameter p : parameters) {  System.out.println(p);  }  System.out.println("----------获取方法抛出的异常----------");  Class[] exceptionTypes = m.getExceptionTypes();  for (Class e : exceptionTypes) {  System.out.println(e);  }  System.out.println("----------方法运行----------");  Student s=new Student();  m1.setAccessible(true);  //返回值  String sdz = (String)m1.invoke(s, "酸豆汁儿");  System.out.println(sdz);  
}

运行结果

----------获取所有公共方法对象(包含父类中方法)----------
public void Demo4.Student.setAge(int)
public int Demo4.Student.getAge()
public java.lang.String Demo4.Student.getName()
public java.lang.String Demo4.Student.toString()
public void Demo4.Student.sleep()
public void Demo4.Student.setName(java.lang.String)
public boolean java.lang.Object.equals(java.lang.Object)
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()
public final void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
----------获取所有方法对象----------
private java.lang.String Demo4.Student.eat(java.lang.String)
public void Demo4.Student.setAge(int)
public int Demo4.Student.getAge()
public java.lang.String Demo4.Student.getName()
public java.lang.String Demo4.Student.toString()
public void Demo4.Student.sleep()
public void Demo4.Student.setName(java.lang.String)
----------获取单个公共方法对象----------
public int Demo4.Student.getAge()
----------获取单个方法对象----------
private java.lang.String Demo4.Student.eat(java.lang.String)
----------获取方法的修饰符----------
1
----------获取方法的名字----------
getAge
----------获取方法的形参----------
java.lang.String arg0
----------获取方法抛出的异常----------
class java.io.IOError
class java.io.IOException
----------方法运行----------
在吃:酸豆汁儿
返回值测试

四、反射的作用(附综合练习)

(1)获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
(2)结合配置文件,动态的创建对象并调用方法

练习 1:保存对象数据

将对象所有的字段名和值,保存到文件中去
结果如下(以接下来的 Student 类为例)

name=学生1  
age=18  
gender=女  
height=160.0  
hobby=打游戏

Student 类

public class Student {  private String name;  private int age;  private char gender;  private double height;  private String hobby;  public Student() {  }  public Student(String name, int age, char gender, double height, String hobby) {  this.name = name;  this.age = age;  this.gender = gender;  this.height = height;  this.hobby = hobby;  }  public String toString() {  return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}";  }  
}

测试类

public static void main(String[] args) throws IllegalAccessException, IOException {  Student s=new Student("学生1",18,'女',160,"打游戏");  saveObject(s);  
}  private static void saveObject(Object obj) throws IllegalAccessException, IOException {  Class clazz= obj.getClass();  BufferedWriter bw=new BufferedWriter(new FileWriter("Z:\\code\\Develop_test\\java\\javacode\\Day-33-反射\\src\\Demo5\\Object"));  //获取所有成员变量  Field[] ds = clazz.getDeclaredFields();  for (Field d : ds) {  d.setAccessible(true);  //获取成员变量名  String name = d.getName();  //获取变量值  Object value = d.get(obj);  bw.write(name+"="+value+"\n");  }  bw.close();  
}

练习 2:利用反射动态的创建对象和运行方法

反射可以与配置文件结合,动态的创建对象,并调用方法

Student 类

public class Student {  private String name;  private int age;  public Student() {  }  public Student(String name, int age) {  this.name = name;  this.age = age;  }  public void study(){  System.out.println("在学习");  }  
}

Properties 配置文件 (Student 全类名为 Demo6.Student)

classname=Demo6.Student
method=study

测试类

public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {  //读取配置文件信息  Properties prop=new Properties();  FileInputStream fis=new FileInputStream("Reflect\\prop.properties");  prop.load(fis);  fis.close();  //获取全类名和方法名  String className=(String) prop.get("classname");  String methodName=(String) prop.get("method");  System.out.println(className);  System.out.println(methodName);  //利用反射创建对象并运行方法  Class clazz=Class.forName(className);  //获取构造方法  Constructor con=clazz.getDeclaredConstructor();  Object o=con.newInstance();  System.out.println(o);  //获取并运行方法  Method declaredMethod = clazz.getDeclaredMethod(methodName);  declaredMethod.setAccessible(true);  declaredMethod.invoke(o);  
}

相关文章:

  • 位运算-详细总结
  • 前端-Vue的项目流程
  • 【Unity】一个AssetBundle热更新的使用小例子
  • 2023年408真题及答案
  • transformer读后感
  • QT6 源(77):阅读与注释滚动条 QScrollBar 的源码,其是基类QAbstractSlider 的子类,
  • 数据库原理——E-R图的极速省流理解 例题解析
  • 如何限制pod 进程/线程数量?
  • Python基本环境搭配
  • C++ 的动态多态
  • C语言易混淆知识点详解
  • 刷leetcodehot100返航版--哈希表5/5、5/6
  • FTP/TFTP/SSH/Telnet
  • 不小心把当前的环境变量路径覆盖掉怎么办
  • 项目管理学习-CSPM(1)
  • 手表功能RunModeTasks
  • 二叉搜索树 AVL树 红黑树 的性质
  • Java——泛型
  • Stellaris 群星 [DLC 解锁] CT 表 [Steam] [Windows SteamOS macOS]
  • rvalue引用()
  • 山东滕州车祸致6人遇难,肇事司机已被刑事拘留
  • 习近平同欧洲理事会主席科斯塔、欧盟委员会主席冯德莱恩就中欧建交50周年互致贺电
  • 独家专访|白先勇:我的家乡不是哪个地点,是中国传统文化
  • 郭旭涛转任河北省科协党组书记、常务副主席,曾任团省委书记
  • 繁荣活跃!“五一”假期全国重点零售和餐饮企业销售额同比增长6.3%
  • 李学明谈笔墨返乡:既耕春圃,念兹乡土