一、反射的概述
1.1什么是反射?
反射(Reflection)是被视为动态语言的关键,反射机制允许程序在运行期间借助于反射取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个class类型的对象(一个类只有一个class对象),这个对象就包含了完整的类的结构信息,可以通过对象看到类。
反射——框架设计的灵魂
总结一下:反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。通俗的来讲,反射就相当于在物体内部放了一面反光镜,透过光可以从外界看到实例对象。
1.2为什么要用反射?
- 获取任意类的名称、包信息、所有属性、方法、注解、类型
- 获取任意对象的属性,并且能改变对象的属性
- 判断任意一个类所具有的成员变量和方法
- 实例化任意一个类的对象
- 实现动态分配、降低代码的耦合度、动态代理等
1.3怎么使用反射
一:Class类:表示一个类的类型,可以通过它获取类的构造函数、方法、字段等信息。Class类是反射机制的核心类之一。它代表了一个类的类型,可以用来获取该类的构造函数、方法、字段等信息,也可以用来创建该类的对象。
Class cs = Class.forName("com.包名.reflection.文件名"); 文件名 jg= (文件名)cs.newInstance();
二:Constructor类:表示一个类的构造函数,可以通过它创建对象。在Java反射机制中,Constructor类表示一个类的构造函数,可以用来创建该类的实例对象。
Class cs = Class.forName("com.包名.reflection.文件名"); Constructor constructor = cs.getConstructor(String.class); 文件名 jg= (文件名)constructor.newInstance();
三:Method类:表示一个类的方法,可以通过它调用类的方法。Method类是用于表示类或接口的方法的反射机制类。它包含有关方法名称,参数类型,返回类型,访问修饰符等信息的元数据。
1.4.反射相关的主要API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量
- java.lang.reflect.Constructor:代表类的构造器
二、理解Class类
2.1反射实现的方式
- 1.通过运行时类的属性:类名.class
- 2.通过运行时类的对象:对象名.getClass()
- 3.通过Class的静态方法:Class.forName("类的路径");
- 4.通过类的加载器:classLoader
2.2获取Class实例的几种方式
@Test public void test1()throws Exception { //1.调用运行时类的静态属性:class Class cs = User.class; System.out.println(cs); //2.调用运行时类的对象:getClass() User1 u1 = new User(); Class cs = u1.getClass(); //3.调用class的静态方法forName(String className) String ClassName = "com.xiao._class.User"; Class cs = Class.forNmae(classname); }
2.3Calss实例指向结构
2.4反射的优缺点
优点:能够动态获取运行时类的实例,提高灵活性,实现框架和插件,动态代理。
缺点:反射的性能较低,需要解析字节码文件,并解析内存中的对象
三、类的加载
3.1什么是类加载器
类加载器(Class Loader)负责将JVM中的字节码转化为能够被JVM执行的类,在JVM运行时,会根据需要动态创建类,启动类加载器会首先加载程序中的核心类库,然后通过双亲委派模型逐层向下加载依赖类。类加载器可以分为三种:启动类加载器、扩展类加载器和应用程序类加载器。
(1)显式加载:在代码中,通过调用 ClassLoader 加载 Class 对象,如:直接使用 Class.forName(name)、this.getClass().getClassLoader().loadClass() 加载 Class 对象
(2)隐式加载:不直接在代码中调用 ClassLoader 方法加载 Class 对象,而是通过虚拟机自动加载到内存中,如:在加载某个类的 .class 文件时,该类的 .class 文件中引用另外一个类的对象,此时额外引用的类将通过 JVM 自动加载到内存中
3.2加载过程
过程一:类的装载(loading)
将类的class文件读入内存,并为之创建一个java.lang.Class对象。
过程二:连接(Linking)
- 验证(Verify):确保加载的类的信息符合JVM规范。
- 准备(Prepare):正式为变量(static)分配内存并设置类变量默认初始值
- 解析(Resolve):虚拟机常量池的符号引用(常量名)替换为直接引用(地址)的过程。
过程三:初始化(Initialization)
- 执行类构造器<clinit>()方法的过程
- 类构造器<clinit>()方法是由编译期自动收集类中所有变量类的赋值动作和静态代码块中合并语句。
3.3类加载器分类
启动类加载器(Bootstrap Class Loader)是Java虚拟机内部的一种特殊的类加载器,它负责加载JDK自带的核心类库,如Java语言的基础类,以及其他的一些Java平台核心类,例如java.lang.*、java.util.*等。启动类加载器是Java虚拟机实现的一部分,是由Java虚拟机自己实现的,并不是Java类,因此无法在Java程序中直接访问。启动类加载器是Java类加载器中最顶层的类加载器,它没有父类加载器。
扩展类加载器(Extension Class Loader)是Java虚拟机中一种类加载器,其主要负责加载Java运行环境中的扩展类库。在Java运行环境中,扩展类库被存储在JRE的lib/ext目录下,扩展类加载器会自动加载该目录下的类,并将其包含在JVM的classpath中。
应用程序类加载器(Application Class Loader)是Java虚拟机中的一种类加载器,其主要负责加载Java应用程序中的类。在Java应用程序中,应用程序类一般是应用程序自己开发的,或者是第三方库提供的。(他们之间并不存在继承关系)
3.4反射的应用
四、java相关小知识