Java反射的入口,Method,Field

本文详细介绍了Java反射机制,包括反射的入口java.lang.Class,以及如何获取和使用Class对象。讨论了Class的获取方式,如通过对象的getClass(),类名.class,Class.forName()等。此外,还讲解了反射在访问和修改成员变量及调用方法上的应用,强调了反射在运行时检查和修改对象信息的能力,但同时也指出其带来的性能开销。
摘要由CSDN通过智能技术生成

1.Class反射的入口

什么是 Reflection 反射,为什么要用它

Java 强类型语言,但是我们在运行时有了解、修改信息的需求,包括类信息、成员信息以及数组信息

Java 中 Reflection 和 Introspection 区别?

说起反射,还有一个相似的概念 ‘Introspection’,字面意思是“自省、内省”,它们之间的区别如下:

  • 内省
    • 在运行时检查一个对象的类型或者属性
    • 最常见的例子就是运行时通过 a instanceof A 来判断 a 对象的类型
  • 反射
    • 用来在运行时检查或者修改一个对象信息
    • 可以用来实现看似不可能的操作,比如访问私有方法,动态创建对象

反射的入口:java.lang.Class

日常开发中的对象,分为两种,基本类型引用类型

  • 基本类型

    ,(固定的 8 种)

    • 整数:byte, short, int, long
    • 小数:float, double
    • 字符:char
    • 布尔值:boolean

引用类型

  • 所有的引用类型都继承自 java.lang.Object
  • 类,枚举,数组,接口都是引用类型
  • java.io.Serializable 接口,基本类型的包装类(比如 java.lang.Double)也是引用类型

对每一种对象,JVM 都会实例化一个 java.lang.Class 的实例,java.lang.Class 为我们提供了在运行时访问对象的属性和类型信息的能力。Class 还提供了创建新的类和对象的能力。最重要的是,Class 是调用其他反射 API 的入口,我们必须先获得一个 Class 实例才可以进行接下来的操作。

得到一个Class对象

1.Object.getClass方法

如果我们已经拿到了以恶对象,可以很方便的使用它的getClass方法获得一个Class对象

Class c = "shixinzhagn.top".getClass();

此时返回的对象是String类型

2.class语法

如果我们当前没有某个类的u第项,无法使用getClass()方法,还可以使用另外一种方法获取Class,在要获取的类名后加上.class

Integer.class.newInstance();
int.class.newInstance();

3.Class.forName()方法获取

如果我们拥有一个类的完整路径,就可以使用Class.forName()来得到相应的Class,这个方法只能用于引用类型

Class<?>c=Class.forName("java.lang.String");
Class<?>aClass=Class.forName("top.test.beans.BookBean");

4.静态属性TYPE

对于基本类型和void的包装类,还可以使用静态属性TYPE。每个包装类都有TYPE属性

public static final Class<Double> TYPE =(Class<Double>double[].class.getComponentType());

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D9xv4tQX-1601911061499)(C:\Users\adim\AppData\Roaming\Typora\typora-user-images\image-20201005200451774.png)]

5.返回Class的方法

如果我们已经有了一个Class,可以使用下面的一些方法来获得他相关的类

Class.getSuperclass():返回调用类的父类

Class.getClass():返回调用类的所有公共类,接口,枚举组成的Class数组,包括继承的

Class.getDeclaredClassses():返回调用类显式声明的所有类,接口,枚举组成的Class数组

返回类/属性/方法/构造器所在的类

Class.getDeclaringClass()

java.lang.reflect.Field.getDeclaringClass()

java.lang.reflect.Method.getDeclaringClass()

java.lang.reflect.Constructor.getDeclaringClass()

Class的修饰符:Modifier

一个Class可以被一下修饰符的一种或者多种修饰

访问权限控制符:public protected private

抽象的,需要实现的: abstract

限制只能有一个实例的:static

不允许修改的:final

线程同步锁:synchronized

原生函数:native

采用严格的浮点精度:strictfp

接口

注解

当然上面的修饰符不是所有 Class 都可以修饰,比如:

Interface 不能是 final 的
enum 不能是 abstract 的
`java.lang.reflect.Modifier` 提供了对 Class 修饰符的解码,我们可以使用 `Class.getModifiers()` 获得调用类的修饰符的二进制值,然后使用 `Modifier.toString(int modifiers)` 将二进制值转换为字符串,`Modifier.toString()` 方法

Class成员:Member

java.lang.reflect.Member:是一个接口,代表Class的成员,每一个成员都有类型,分别是否从父类继承,还有是否可以直接访问。

Member有三个实现类:

java.lang.reflect.Constructor:表示该 Class 的构造函数

java.lang.reflect.Field:表示该 Class 的成员变量

java.lang.reflect.Method:表示该 Class 的成员方法

获取构造函数:

java.lang.Class提供了一下方法用于获取该类的构造函数:构造函数无法从父类继承

2.Java反射:Field(成员变量)

java.lang.reflect.Field 提供了两个方法获去变量的类型:

  • Field.getType():返回这个变量的类型
  • Field.getGenericType():如果当前属性有签名属性类型就返回,否则就返回 Field.getType()****

获取成员变量的修饰符

成员变量可以被以下修饰符修饰:

  • 访问权限控制符:public, protected, private
  • 限制只能有一个实例的:static
  • 不允许修改的:final
  • 不会被序列化:transient
  • 线程共享数据的一致性:volatile
  • 注解

类似获取 Class 的修饰符,我们可以使用 Field.getModifiers() 方法获取当前成员变量的修饰符。
返回 java.lang.reflect.Modifier 中定义的整形值。

由于 Field 间接继承了 java.lang.reflect.AnnotatedElement ,因此运行时也可以获得修饰成员变量的注解,当然前提是这个注解被 java.lang.annotation.RetentionPolicy.RUNTIME 修饰。

获取和修改成员变量的值

拿到一个对象后,我们可以在运行时修改它的成员变量的值,对运行时来说,反射修改变量值的操作和类中修改变量的结果是一样的。

由于 Field 继承自 AccessibleObject , 我们可以使用 AccessibleObject.setAccessible() 方法告诉安全机制,这个变量可以访问。

因此上面的例子中,声明这个变量是可访问的:wannaPlayGame.setAccessible(true),运行就正常了。

总结

**在使用反射修改某个对象的成员变量前你要明白,这样做会造成一定程度的性能开销,因为在反射时这样的操作需要引发许多额外操作,比如验证访问权限等。**只在特殊情况下这么做。

3.Java反射:Method(成员方法):

Method 介绍

继承的方法(包括重载、重写和隐藏的)会被编译器强制执行,这些方法都无法反射。

因此,反射一个类的方法时不考虑父类的方法,只考虑当前类的方法。

每个方法都由 修饰符、返回值、参数、注解和抛出的异常组成。

java.lang.reflect.Method 方法为我们提供了获取上述部分的 API。

获取方法的参数名称

从 JDK 1.8 开始,java.lang.reflect.Executable.getParameters 为我们提供了获取普通方法或者构造方法的名称的能力。

在 JDK 中 java.lang.reflect.Methodjava.lang.reflect.Constructor 都继承自 Executable,因此它俩也有同样的能力。

然而在 Android SDK 中 Method, Constructor 继承自 AbstractMethod,无法获得方法的参数名:

获取方法的修饰符

方法可以被以下修饰符修饰:

  • 访问权限控制符:public, protected, private
  • 限制只能有一个实例的:static
  • 不允许修改的:final
  • 抽象,要求子类重写:abstract
  • 预防重入的同步锁:synchronized
  • 用其他语言实现的方法:native
  • 严格的浮点型强度:strictfp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值