📋 个人简介
- 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
- 📝 个人主页:馆主阿牛🔥
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:java 小白到高手的蜕变🍁
- 💬格言:要成为光,因为有怕黑的人!🔥
目录
- 📋 个人简介
- 前言
- 反射的概述
- java反射机制提供的功能
- java反射相关的主要API
- Class类的理解
- 获取Class实例的4种方式
- 哪些类型可以有Class对象
- 理解类的加载过程
- ClassLoader类加载器的理解
- 结语
前言
本节将学习java中的反射,上篇主要讲解一些概念以及一些需要了解的东西,下篇我将总结如何使用反射调用类的内部结构!
反射的概述
- 反射是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
- 加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。
java反射机制提供的功能
>在运行时判断任意一个对象所属的类
>在运行时构造任意一个类的对象
>在运行时判断任意一个类所具有的成员变量和方法
>在运行时获取泛型信息
>在运行时调用任意一个对象的成员变量和方法
>在运行时处理注解
>生成动态代理
java反射相关的主要API
java.lang.Class :代表一个类
java.lang.reflect.Method :代表类的方法
java.lang.reflect.Field :代表类的成员变量
java.lang.reflect.Constructor :代表类的构造器
…
Class类的理解
1.类的加载过程:
程序经过 javac.exe 命令以后,会生成一个或多个字节码文件(. class 结尾)。接着我们使用 java.exe 命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为 Class 的一个实例。
2.换句话说, Class 的实例就对应着一个运行时类。
3.加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类。
获取Class实例的4种方式
首先我们随便创建一个类,然后我们用四种不同的方式来获取这个类的Class实例。
public class People {
String name;
int age;
public People(){
}
public People(String name, int age) {
this.name = name;
this.age = age;
}
}
四种方式:
package java反射;
/**
* @Author:Aniu
* @Date:2023/1/14 19:00
* @description TODO
*/
public class Demo {
public static void main(String[] args) {
// 获取Class实例的4种方式
// 方式一: 调用运行时类的属性 .class
Class cl1 = People.class;
System.out.println(cl1);
// 方式二 :通过运行时类的对象
People p = new People();
Class cl2 = p.getClass();
System.out.println(cl2);
// 方式三:调用Class的静态方法 forName(String classPath)
try {
Class cl3 = Class.forName("java反射.People");
System.out.println(cl3);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = People.class.getClassLoader();
try {
Class cl4 = classLoader.loadClass("java反射.People");
System.out.println(cl4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
从使用频率上来说,第三种最常用,包括我们看到的JDBC数据库连接中也是使用了第三种!
哪些类型可以有Class对象
(1) class:
外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
(2) interface :接口
(3) [ ]:数组
(4) enum :枚举
(5) annotation :注解@interface
(6) primitive type :基本数据类型
(7) void
Class c1= Object.class;
Class c2= Comparable.class; // 接口
Class c3= String[].class;
Class c4= int[][].class;
Class c5= ElementType.class; //枚举
Class c6= Override.class; //注解
Class c7= int.class;
Class c8= void.class;
Class c9= Class.class;
// 输出c1-c9
Class[] clas = new Class[]{c1,c2,c3,c4,c5,c6,c7,c8,c9};
for(Class item: clas){
System.out.println(item);
}
int[] a = new int[10];
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
//只要元素类型与维度一样,就是同一个 Class
System.out.println(c10==c11);
理解类的加载过程
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化
-
加载:将 class 文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的 java.lang.Class 对象,作为方法区中类数据的访问入口(即引用地址)。所有需要访问和使用类数据只能通过这个 Class 对象。这个加载的过程需要类加载器参与。
-
链接:将 Java 类的二进制代码合并到 JVM 的运行状态之中的过程。
>验证:确保加载的类信息符合 JVM 规范,例如:以 cafe 开头,没有安全方面的问题
>准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
>解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。 -
初始化:
>执行类构造器 <clinit >() 方法的过程。类构造器 <clinit >() 方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
>当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
>虚拟机会保证一个类的 <clinit >() 方法在多线程环境中被正确加锁和同步。
ClassLoader类加载器的理解
这张图是java语言执行的过程,其中就有类加载器(或者类装载器)。
类加载器的作用:
- 类加载的作用:将 class 文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的 java.lang.Class 对象,作为方法区中类数据的访问入口。
- 类缓存:标准的 JavaSE 类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过 JVM 垃圾回收机制可以回收这些 Class 对象。
JVM规范定义了以下类型的类的加载器:
//对于自定义类,使用系统类加载器进行加载
ClassLoader classLoader = People.class.getClassLoader ();
System.out.println (classLoader);
//调用系统类加载器的 getParent():获取扩展类加载器
ClassLoader classLoader1 = classLoader.getParent();
System.out.println(classLoader1);
//调用扩展类加载器的 getParent():无法获取引导类加载器
//引导类加载器主要负责加载 java 的核心类库,无法加载自定义类的。
ClassLoader classLoader2 = classLoader1.getParent();
System.out.println(classLoader2);
//String是由引导类加载器加载的,无法获取
ClassLoader classLoader3 = String.class.getClassLoader ();
System.out.println(classLoader3);
使用ClassLoader也可以加载配置文件,这里不再总结,感兴趣的可以去了解以下!
结语
如果你觉得博主写的还不错的话,可以关注一下当前专栏,博主会更完这个系列的哦!也欢迎订阅博主的其他好的专栏。
🏰系列专栏
👉软磨 css
👉硬泡 javascript
👉flask框架快速入门