反射机制

Java基础 专栏收录该内容
10 篇文章 0 订阅

概述

反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。
在这里插入图片描述

Class类

在Object类中定义了以下的方法,此方法将被所有子类继承:public final Class getClass(),返回值的类型是一个Class类,此类是Java反射的源头。

  • 常用方法:
    在这里插入图片描述

获取Class类实例的四种方法

  • 已知具体的类,通过类的class属性获取:
    Class clazz = String.class;
  • 已知某个类的实例,调用该实例的getClass()方法获取Class对象:
    int[] a = new int[10];
    Class clazz = a.getClass();
  • 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException:
    Class clazz = Class.forName(“java.lang.String”);
  • 通过类的加载器获取:
    ClassLoader cl = this.getClass().getClassLoader();
    Class clazz = cl.loadClass(“类的全类名”);

类的加载器ClassLoader

类加载器作用是用来把类(class)装载进内存的。JVM 规范定义了如下类型的类的加载器。
在这里插入图片描述

  • 类的加载过程:
    当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。
    在这里插入图片描述
public class ClassLoaderLen {
    public static void main(String[] args) {
        System.out.println(A.m);
    }
}
class A{
    static {
        m = 300;
    }
    static int m = 100;
}
(1)加载;
(2)链接结束后m=0;
(3)初始化后,m的值由<clinit>()方法执行决定,这个A的类构造器<clinit>()方法由类变量的赋值和静态代码块中的语句按照顺序合并
产生,类似于:
	<clinit>(){
		m = 300;
		m = 100;
	}
  • 什么时候发生类的初始化:
    (1)类的主动引用会发生类的初始化,例如当虚拟机启动,先初始化main方法所在的类;new一个类的对象;调用类的静态成员(除了final常量)和静态方法;使用java.lang.reflect包的方法对类进行反射调用;当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类。
    (2)类的被动引用不会发生类的初始化,例如当访问一个静态域时,只有真正声明这个域的类才会被初始化,当通过子类引用父类的静态变量,不会导致子类初始化;通过数组定义类引用,不会触发此类的初始化;引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)。

创建运行时类的对象

//1.根据全类名获取对应的Class对象
String classPath = "Java集合.Student";
Class clazz = Class.forName(classPath);
//2.调用指定参数结构的构造器,生成Constructor的实例
Constructor constructor = clazz.getConstructor(String.class,int.class);
//3.通过Constructor的实例创建对应类的对象,并初始化类属性
Student student = (Student) constructor.newInstance("Tom",20);
System.out.println(student);//Student{name='Tom', age=20}

获取运行时类的完整结构

通过反射获取运行时类的完整结构,包括Field、Method、Constructor、Superclass、Interface、Annotation。

调用运行时类的指定结构

//1.获取指定的某个方法,参数1为指定获取的方法的名称,方法2为指定获取的方法的形参列表
Method testReflect = clazz.getDeclaredMethod("testReflect", String.class);
//2.若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法
testReflect.setAccessible(true);
//3.调用方法的invoke(),参数1为方法的调用者,参数2为给方法形参赋予的实参,invoke()的返回值即为对应类中调用方法的返回值
//若原方法为静态方法,此时形参Object obj可为null
//若原方法形参列表为空,则Object[] args为null
Object param = testReflect.invoke(student, "param");

//1.获取运行时类中指定变量名的属性
Field name = clazz.getDeclaredField("name");
//2.保证当前属性是可访问的
name.setAccessible(true);
//3.设置指定对象obj上此Field的属性内容
name.set(student,"peter");
//4.取得指定对象obj上此Field的属性内容
Object o = name.get(student);

反射的应用:动态代理

  • 0
    点赞
  • 2
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页

打赏作者

AndrewBest

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值