一、Java框架基础01反射

一、反射

1.1 Java 反射概述

反射机制是 Java 语言的特性之一,是Java被视为动态语言的一个关键特性,其核心是指程序运行时动态加载类并获取类的详细信息

1.1.1 什么是反射

  • 反射是一种能力,能够自描述和自控制,在运行状态中,动态获取类信息及调用类的属性和方法
  • Java 反射的 3 个动态特性
    • 运行时创建实例
    • 运行期间调用方法
    • 运行时更改属性

1.1.2 反射的原理

  • 了解反射的原理,先回顾 Java 程序是如何执行的,如下图

搜狗截图20230721214724

  • 之前所运行的程序,都是在编译时就已经链接了所需的类

  • 而 Java 反射机制则运行程序在运行时在加载,使用那些在编译时完全未知的类

  • 反射机制允许程序创建和控制任何类的对象,无需提前硬编码目标类

1.1.3 反射的用途

  • 反射机制允许 Java 程序加载一个运行时才能得知其名称的类,获取该类的所有信息
  • 并且可以生成其实例,对其属性赋值或调用其方法
  • 通过 Java 反射可以实现对类的实例的构造,探知类所具有的方法和属性,调用任意一个实例的方法等等
  • Java 反射机制可以探知类的基本结构,这种能力称之为 Java 类的 “自审”
  • 反射机制是构建框架技术的基础所在

1.1.4 反射常用的 API

使用 Java 反射技术,常用的类如下

类名说明
java.lang.Class <T>反射的核心类,反射所有的操作都是围绕该类来生成
通过 Class 类可以获取类的属性、方法等内容
java.lang.reflect.Construcrot<T>表示类的构造方法
java.lang.reflect.Field 类表示类的属性,可以获取和设置类中属性的值
java.lang.reflect.Method 类表示类的方法,可以用来获取类中方法的信息或执行方法

1.2 反射的应用(获取类的信息)

在 Java 程序中使用反射的基本步骤如下

  • 导入 java.lang.reflect 包中的相关类
  • 获取需要操作的类的 Class 实例
  • 调用 Class 实例的方法获取 Filed、Method 等实例
  • 使用反射 API 操作实例成员

当一个类或接口被加载后,从系统当中可以等到一个代表该类或接口的 Class 类型的实例,通过该实例就可以访问到 Java 虚拟机找那个的这个类或接口

1.2.1 获取 Class 实例

获取 Class 实例主要有三种方法,可以根据实际情况灵活选择

  • 调用类或接口实例的 getClass() 方法
    • 所有类和接口的实例都可以调用 getClass() 方法
    • 该方法会返回该实例的所属类型对应的 Class 实例
Person person=new Person();
Class c1=person.getClass();
  • 调用类或接口的 class 属性
    • 在某些类或接口没有完成实例或无法创建实例时
    • 可以通过其 class 属性获取所对应的 Class 实例
    • 这种方法需要在编译期就知道类或接口的名称
 Class c2=Person.class;
  • 使用 Class.forName()
    • 编码时无法确认具体类型,需要程序在运行时根据情况灵活加载
    • 可以使用 Class.forName() 方法,该方法是静态的,需要手动传入字符串参数
    • 字符串参数的值是某个类,即包含类包名和完整类名
Class c3=Class.forName("com.mysql.cj.jdbc.Driver");

1.2.2 从Class 实例获取信息

在获取了对应的 Class 实例后,可以使用 Class 实例的方法来获取该类型的信息

  • 获取对应类型基本信息的方法
方法说明
String getName()以字符串形式返回该类型的名称,即包名加类名
Stirng getSimpleName()以字符串形式返回该类型的简称,即类名
Package getPackage()获取该类型所在的包
Class getSuperclass()返回该类型的超类的 Class 实例,即该类型的父类的 Class 实例
Class [] getInterfaces()返回该类型所实现的全部接口的 Class 实例
int getModifiers()返回该类型的所有修饰符,由 public、protected、private、final、static、abstract
等对应的 int 常量组成,返回的整数应使用 Modifier 工具类来解码,才可以判断修饰符的构成
Class [] getDeclaredClasses()返回该类型中包含的全部内部类的 Class 实例
Class getDeclaringClass()返回该类型所在的外部类的 Class 实例,例如 A类内有内部类B,B.getDeclaringClass()
则返回 A类的 Class 实例
  • 获取对应类型所包含构造方法的方法
方法说明
Constructor getConstructor(Class … parmas)返回该类型指定参数列表的 public 方法
Constructor[] getConstructors()返回该类型的所有 public 构造方法
Constructor getDeclaredConstructor(Class … parmas)返回该类型的指定参数列表的构造方法,访问级别不限
Constructor[] getDeclaredConstructors()返回该类型的所有构造方法,访问级别不限
  • 获取对应类型所含属性的方法
方法说明
FieId getFieId(String name)返回该类型中指定名称的 public 属性,name 参数用于指定属性名称
FileId[] getFieIds()返回该类型中的所有 public 属性
FileId getDeclaredFieId(String name)返回该类型中指定名称的属性,与属性的访问级别无关
FileId[] getDeclaredFieIds()返回该类型中的全部属性,与属性的访问级别无关
  • 访问类包含方法的方法
方法说明
Method getMethod(String name,Class … parmas)返回该实例中指定的 public 方法,name参数用于
指定方法名称,params 参数指定参数列表
Method[] getMethods()返回该实例中所有的 public 方法
Method getDeclaredMethod(String name,Class … params)返回该实例中指定的方法,与方法的访问级别无关
Method[] getDeclaredMethods()返回该实例中的全部方法,与方法的访问级别无关

从 Class 实例获取信息,当需要传递参数时,也是传递类型的实例,例如

  • getConstructor(String.class,List.class)
  • 上面就是传递了一个 String 类型以及 List 集合类型 的参数

1.2.3 创建实例

通过反射来创建 Java 类型的实例有以下两种方式

  • 使用 Class 实例的 newInstance() 方法创建相关类型的实例
  • 使用 Constructor 实例创建相关类型的实例
  • 示例
Object o1 = c1.newInstance();
Object o2 = c1.getConstructor().newInstance();

1.2.4 访问类的属性

使用 File 实例可以对属性进行取值或赋值操作

访问属性的方法

方法说明
xxx getXxx(Object obj)xxx 表示b中基本数据类型之一,如 int getInt(Object obj)。obj
为类的实例,如果 FieId 实例表示的是一个静态方法,则 obj 可以为空
Obejct get(Object obj)以 Object 类型返回 obj中相关属性的值
void setXxx(Object obj,xxx val)以 obj 中相关属性的值设置为 val。xxx 为 8中基本数据类型之一
void ser(Object obj,Object val)以 obj 中相关属性的值设为 val
void setAccessible(boolean flag)对相关属性设置访问权限,这是为 true 可以禁止 Java 语言的访问检查
也就是可以对私有属性赋值

示例

package Test01;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test01 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException {
        Class<?> c1 = Person.class;
//        创建实例
        Object o = c1.newInstance();
//        获取  private String name; 属性
        Field name = c1.getDeclaredField("name");
//        禁用java语言访问检查
        name.setAccessible(true);
//        取值
        System.out.println(name.get(o));
//        赋值
        name.set(o,"巧克力");
        System.out.println(name.get(o));
//
    }
}

1.2.3 调用类的方法

  • Method 类中包含一个 invoke() 方法,通过 invoke() 方法,Method 实例可以调用 Java 类的实例方法和静态方法

  • 此外还有一个方法,可以设置私有方法可访问,关键字为 setAccessible(true)

  • invoke() 方法定义如下

Object invoke(Object obj,Object ... args);
  • obj 是执行该方法的对象,args 是执行该方法是传入的参数
  • 例如 Person 类当中有一个 public void show(int agrs) 方法,演示
package Test01;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test01 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException, ClassNotFoundException, NoSuchFieldException {
        Class<?> c1 = Person.class;
//        创建实例
        Object o = c1.newInstance();
//        获取 public void show(int agrs) 方法
        Method show = c1.getDeclaredMethod("show", int.class);
        show.invoke(o,123);
    }

}

    Class<?> c1 = Person.class;

// 创建实例
Object o = c1.newInstance();
// 获取 public void show(int agrs) 方法
Method show = c1.getDeclaredMethod(“show”, int.class);
show.invoke(o,123);
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值