JAVA反射学习笔记

了解反射

Java反射是指在程序运行期获取对象所有信息。

简单来说,我们可以在对一个实例一无所知的情况下通过反射来获取、调用对象的字段(Field)、方法(Method)、通过构造方法获取实例以及了解类的继承关系。

你一定记得,在学习JDBC(Java DataBase Connectivity,Java程序访问数据库的标准接口)的时候,获取一个数据库连接,首先要加载驱动:

Class.forName("com.mysql.jdbc.Driver");

如果项目中添加了MySQL驱动的jar包,那么上面的语句就可以将Driver类成功注册到java.sql.DriverManager当中,然后再使用Connection con = DriverManager.getConnection(url , username , password ) ;就可以获取数据库连接。

Class.forName("XXX");语法就是利用反射获取Class的一种,除此之外还有其他两种,后续会说到。

Class对象

JVM每加载一个class到内存,就会为其创建一个Class对象实例与之关联。

例如:JVM加载String类时,首先加载String.class文件,经过加载->链接->初始化将类加载到内存,然后会为String类创建一个Class实例:

Class cls = new Class(String);

这个Class实例是由JVM内部来创建的,通过JDK源码我们可以看出:

public class Class{
	private Class(){}
}

构造方法是私有的,所以我们自己写的Java程序是无法创建的。(这里可以留一个问号,因为文章摘要写的是私有构造并非一定访问不了,这里怎么就不能自己创建了呢?)

Class包含了它所指向的class的所有信息:包括类名、包名、父类、实现的接口、所有方法、字段等。

获取Class有三种方式:

  • 类名.class
	Class cls = String.class;
  • 对象名.getClass()
	String str = "hello";
	Class cls = str.getClass();
  • Class.forName(“java.lang.String”)
	Class cls = Class.forName("java.lang.String");

上述三种方法获取的Class实例都是同一个实例,因为Class实例在JVM中是唯一的,我们可以通过==来比较两个Class实例是否相同:

// 判断两个Class是否是同一个实例,使用 == 和 instanceof 的区别是
// instanceof 不仅判断是否是同一个Class,还会判断前者是否是后者的子类
Integer n = new Integer(123);

boolean b1 = n instanceof Integer; // true,因为n是Integer类型
boolean b2 = n instanceof Number; // true,因为n是Number类型的子类

boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.class
boolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class

注:除了类、接口、数组会有对应的Class实例外,JVM也为每一种基本类型如int创建Class,通过int.class访问。

如果我们获取了Class,我们就可以用它来创建对象实例以及实现各种 非 常规*的操作。

访问字段 Field

通过Class实例,可以使用以下方法来获取对象的字段信息:

根据字段名获取某个字段

  • Field getField(name):获取某个public Field
    (包括从父类继承过来的字段)
  • Field getDeclaredField(name):获取当前类的某个 Field
    (不包括父类)

获取字段列表

  • Field[] getFields():获取所有public Field
    (包括父类)
  • Field[] getDeclaredFields():获取当前类的 所有 Field
    (不包括父类)

注意到包含 Declared关键字的方法可以访问类的所有字段,包括private字段,然后通过setAccessible(true)方法可以获取字段的值。

Field对象包含了一个字段的所有信息:

  • getName(): 返回字段名称
  • getType(): 返回字段类型,也是Class实例,例如String.class
  • getModifiers: 获取字段的修饰符,返回值是int类型,不同bit表示不同含义

以String类的value字段为例:

public final class String {
	// value 字段定义
	private final byte[] value;
}

利用反射获取value字段的信息

// 获取String类所有字段信息,包括private字段
Field field = String.class.getDeclaredField("value");

field.getName(); // value
field.getType(); // class [B 表示byte[]类型

int mofify = field.getModifiers();
Modifier.isFinal(modify); // true
Modifier.isPublic(modify); // false
Modifier.isProtected(modify); // false
Modifier.isPrivate(modify); // true
Modifier.isStatic(modify); // false

通过Field获取属性的值

通过Field设置属性的值

调用方法 Method

通过Class对象可以访问字段及获取字段的值,同样的,也可以通过它来获取一个类的方法信息:

根据字段名获取某个方法,通过参数列表来区分重载方法

  • Method getMethod(name, Class...):获取某个public Method
    (包括从父类继承过来的方法)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个 Method(不包括父类)

获取方法列表

  • Method[] getMethods():获取所有public Method
    (包括从父类继承过来的方法)
  • Method[] getDeclaredMethods():获取当前类的 所有 Method
    (不包括父类)

一个Method包含一个方法的所有信息:

  • getName(): 返回方法名称
  • getReturnType() 返回方法返回值类型,Class类型
  • getParameterTypes(): 返回方法参数类型,Class数组
  • getModifiers(): 返回方法的修饰符,int类型,不同的bit表示不同的含义

调用方法
调用静态方法
调用非public方法
多态

调用构造方法 Constructor

获取继承关系

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hongmin.shm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值