Java进阶 - 反射

概念

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象,必须先得到代表的字节码的ClassClass类用于表示.class文件(字节码)

使用场景

反射在Java中有许多应用场景,以下是一些常见的使用情况:

  1. 框架和库:许多Java框架和库使用反射来实现动态加载和配置。例如,Spring框架使用反射来实现依赖注入和AOP编程。
  2. 序列化和反序列化:Java的序列化和反序列化机制使用了反射。通过反射,可以在运行时动态地读取和写入对象的字段。
  3. 单元测试:JUnit等单元测试框架使用反射来自动化执行测试用例。通过反射,测试框架可以自动发现和执行类中的测试方法。
  4. 动态代理:Java动态代理机制利用了反射来实现代理对象的动态创建和方法调用的拦截。

原理

Java反射的原理基于Java的运行时数据区域(Runtime Data Area)和类加载机制。当Java虚拟机加载一个类时,它将类的字节码文件加载到内存中,并在方法区创建一个Class对象来表示该类。Class对象包含了类的完整信息,包括类的构造函数、方法、字段等。

Java反射提供了以下核心类:

  1. Class类:代表Java中的类或接口。通过Class类,我们可以获取类的构造函数、方法、字段等信息。
  2. Constructor类:代表类的构造函数。通过Constructor类,我们可以创建对象。
  3. Method类:代表类的方法。通过Method类,我们可以调用方法。
  4. Field类:代表类的字段。通过Field类,我们可以访问和修改字段的值。

Type接口

参考资料:Java中的Type - tiger168 - 博客园  

Type是Java 编程语言中所有类型的公共高级接口,也就是Java中所有类型的“爹”,对基本类型、引用类型向上的抽象

Type是个空接口,没有定义任何方法。Type体系中类型的包括:原始类型(Class)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)、类型变量(TypeVariable)、基本类型(Class);

        

  1. 原始类型(Class):不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
  2. 参数化类型(ParameterizedType):就是我们平常所用到的泛型List、Map;
  3. 数组类型(GenericArrayType):并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;
  4. 基本类型(Class):也就是我们所说的java的基本类型,即int,float,double等

Class类(类型类)

参考资料:java反射(特别通俗易懂)_通俗理解java反射-优快云博客

获取Class类方式(3种)

  1. Class.forName(“类名”):这种方式最常用,一般用于从外部文件中读取完整类名,然后据此创建对象Class cls1 = Class.forName("class_relate.Wolf");
  2. 类名.class一般用于参数传递 Class cls2 = Integer.class;
  3. 对象.getClass()一般用于已知某个类的实例,通过此实例来获取它关联的Class对象;

在运行期间,一个类只有一个Class对象产生。

在获得Class类之后,你就可以调用其中的一些方法获得类型的信息了,主要的方法有:

获取构造方法(用于实例化对象)

  • 批量获取

public Constructor[] getConstructors():所有”公有的”构造方法

public Constructor[] getDeclaredConstructors():获取所有的构造方法

  • 单个获取

public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法

public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”,可以是私有的,或受保护、默认、公有;

  • 调用构造方法(实例化对象)

constructorObj.newInstance(Object… initargs):newInstance是 Constructor类的方法(管理构造方法的类),它的返回值是T类型。

获取成员变量并调用

  • 批量获取

Field[] getFields():获取所有的"公有字段";

Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;

  • 单个获取

public Field getField(String fieldName):获取某个"公有的"字段;

public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的);

  • 设置字段的值

fieldObj.setAccessible(true):暴力反射,解除私有限定

fieldObj.set(Object obj,Object value):obj是设置的字段所在的对象;value是为字段设置的值;

获取成员方法并调用

  • 批量获取

public Method[] getMethods():获取所有"公有方法"(包含了父类的方法也包含Object类);

public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的);

  • 单个获取

public Method getMethod(String name,Class<?>... parameterTypes):获取单个公有方法,name是方法名,parameterTypes是形参的Class类型对象(例如:String.class);

public Method getDeclaredMethod(String name,Class<?>... parameterTypes):获取单个方法(包含私有的);

  • 调用方法

moethodObj.invoke (Object obj, Object... args):obj是要调用方法的对象;args调用方式时所传递的实参;

其他常用方法

方法

说明

String getName()

获得该类型的全称名称。

Class getSuperClass()

获得该类型的直接父类,如果该类型没有直接父类,那么返回null。

Type getGenericSuperclass()

获得该类带有泛型的父类

Class[] getInterfaces()

获得该类型实现的所有接口。

Boolean isArray()

判断该类型是否是数组。

Boolean isEnum ()

判断该类型是否是枚举类型。

Boolean isInterface ()

判断该类型是否是接口。

Boolean isPrimitive ()

判断该类型是否是基本类型,即是否是int,boolean,double等等。

ParameterizedType接口

         参考资料:理解 Java 的 ParameterizedType 接口-优快云博客

ParameterizedType 接口继承了Type 接口,它用于表示带有泛型参数的类型,例如 List<String> 或 Map<Integer, String> 等。通过 ParameterizedType 接口,我们可以获取泛型类型的实际参数类型信息,而不仅仅是泛型的类型变量(TypeVariable)。

  1. Type[] getActualTypeArguments(): 返回表示此类型实际类型参数的Type对象数组。返回“<>”里的参数,比如Map<String,Integer>。
  2. Type getRawType(): 返回表示此类型的原始类型的Type对象。返回“<>”前面的类型,比如List<String>。
  3. Type getOwnerType(): 返回表示此类型的所有者类型的Type 对象。

TypeVariable接口

类型变量,即泛型中的变量;例如:T、K、V等变量,可以表示任何类;在这需要强调的是,TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型;

GenericArrayType接口

泛型数组类型,用来描述ParameterizedType、TypeVariable类型的数组;即List<T>[] 、T[]等;

GenericDeclaration接口

Java-Type体系中还有另一个比较重要的接口GenericDeclaration;含义为:声明类型变量的所有实体的公共接口;也就是说该接口定义了哪些地方可以定义类型变量(泛型);

GenericDeclaration下有三个子类,分别为Class、Method、Constructor;也就是说,我们定义泛型只能在一个类中这3个地方自定义泛型;

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值