一、Java框架基础01反射

一、反射

1.1 Java 反射概述

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

1.1.1 什么是反射

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

1.1.2 反射的原理

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

一、Java框架基础01反射_第1张图片

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

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

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

1.1.3 反射的用途

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

1.1.4 反射常用的 API

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

类名 说明
java.lang.Class 反射的核心类,反射所有的操作都是围绕该类来生成
通过 Class 类可以获取类的属性、方法等内容
java.lang.reflect.Construcrot 表示类的构造方法
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);
}

}


你可能感兴趣的:(Java框架基础,java,python,qt)