韩顺平Java | C23 反射Reflection

需求:通过外部文件配置,在不修改源码情况下控制程序(符合设计模式ocp开闭原则:不修改源码的情况下扩容功能)

※反射机制

反射机制允许程序在执行期间借助于ReflectioAPI取得任何类的内部信息(如成员变量,构造器,成员方法),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。
加载完类后,在堆中产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息,通过这个对象得到类的结构,故名曰反射。
在这里插入图片描述

//反射相关的主要类
import java.lang.reflectjava.lang.Class // 代表一个类,Class对象代表某个类加载后在堆中的对象
java.lang.reflect.Method //代表类的方法,Method对象代表某个类的方法
java.lang.reflect.Field //代表类的成员变量,Field对象表示某个类的成员变量
java.lang.reflect.Constructor //代表类的构造方法,Constructor对象表示构造器

优点:动态创建和使用对象(框架底层核心)
缺点:反射基本是解释执行,对执行速度有影响
优化:关闭访问检查。Method、Field和Constructor都有setAccessible()方法,用于启动和禁用访问安全检查的开关,参数值为true表示放射的对象在使用时取消访问检查,提高反射效率,反之false执行。

//相关API:使用Properties类读取配置文件
Properties properties = new Properties();
properties.load(new InputStream("src\\cfg.properties"));
String classfullName = properties.get("classfullName");

反射机制基础代码

Class<?> cls = Class.forName("classfulldName"); //1 获取Class类
Object o = cls.getInstance(); //2 通过Class类获取类对象
Method method = cls.getMethod("methodName");//3 通过Class类获取方法对象
method.invoke(o); //4 通过方法对象反向调用类对象

※Class类

Class对象不是new出来的,而是系统创建的
对于某个类的Class对象,在内存中只有一份,因为类只加载一次

Class类的常用方法

//获得Class类
Class<?> cls = Class.forname(String name); //返回指定类名name的Class对象
//显示
System.out.println(cls); //显示cls对象是哪个类的Class对象 如com.hspedu.Car
System.out.println(cls.getClass()); //显示cls的运行类型 java.lang.Class
System.out.println(cls.getPackage().getName()); //包名 com.hspedu
cls.getName() //类的全路径,全类名 com.hspedu.Car,返回Class对象所表示的实体名称(类、接口、数组、基本类型等)
//获得实例
Object newInstance() //返回Class对象的一个实例
Car car = (Car)cls.newInstance(); 
System.out.println(car); //实际调用toString()
//通过反射得到属性(不能获取私有属性)
Field field = cls.getField("brand");
System.out.println(fieid.get(car));
brand.set(car, "奔驰");//通过反射给属性赋值
//遍历得到所有的属性(字段)
Field[] fields = cls.getFields();
for(Field f : fields){System.out.print(f.getName()); //名称
}

在这里插入图片描述

获取类的Class对象的方式

Class.forName(String classfullname) //代码/编译阶段,应用:多用于配置文件,读取类全路径,加载类.class //加载阶段 应用:多用于参数传递,如通过反射获取构造器对象对象.getClass() //运行阶段 应用:通过创建好的对象获取Class对象//通过类加载器(4种)获取类的Class对象
ClassLoader classLoader = car.getClass().getClassLoader();//先得到类加载器car
Class<?> cls = classloader.loadClass(classAllPath)//通过类加载器得到Class对象基本数据类型.class //基本数据类型(int, char, boolean, float, double, byte, long, short),得int包装类.TYPE // 基本数据类型对应的包装类 Integer, Character, BOOLEAN, DOUBLE, LONG, BYTE... 得int,和上同一个Class类,hashcode()相等

哪些类型有Class对象:

//外部类,成员内部类,静态内部类,局部内部类,匿名内部类
Class<String> aclass = String.class; //外部类class java.lang.String
//interface:接口
Class<Serializable> serializableClass = Serializable.class; //interface java.io.Serializable
//数组
Class<Integer[]> aClass = Integer[].class; //class [Ljava.lang.Inte
Class<float[][]> aClass = float[][].class; //class [[F
//enum:枚举
Class<Thread.State> aClass = Thread.State.class; //class java.lang.Thread$State
//annotation:注解
Class<Derecated> aClass = Derecated.class; //interface java.lang.Deprecated
//基本数据类型
Class<Long> aClass = long.class; //long
//void
Class<Void> voidClass = void.class; //void
Class<Class> classClass = Class.class; //class java.lang.Class

※类加载

静态加载:编译时加载相关类,如果没有则报错,依赖性太强。如new、子类被加载时,父类也加载(继承)、调用类中的静态成员
动态加载:运行时加载需要得类,如果运行时不用该类,即使该类不存在,也不报错,降低了依赖性。如反射
在这里插入图片描述

类加载的五个阶段

在这里插入图片描述

  • 加载阶段:JVM将字节码从不同的数据源(class文件、jar包、网络等)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象
  • 连接阶段-验证:确保Class文件的字节流中包含的信息符合当前虚拟机要求(文件格式验证-是否以魔数oxcafebabe开头-打开编译后class文件可看、元数据验证、字节码验证、负好引用验证),不会危害虚拟机自身安全。可以使用-Xverify:none参数关闭大部分的类验证措施,缩短虚拟机类加载时间
  • 连接阶段-准备:JVM对静态变量,分配内存并默认初始化(对应数据类型默认初始值,如0-int/short、0L-long、null-引用类型、false-boolean等)。内存均在方法区中分配
//类加载的连接阶段-准备,属性/成员变量/字段是如何处理的
class A {public int n1 = 10; //n1是实例属性,不是静态变量,连接准备阶段不分配内存public static n2 = 20; //n2是静态变量,连接准备阶段分配内存,默认初始化0,不是20public static final int n3 = 30; //n3是static final常量,和类/静态变量,一旦赋值就不变,n3=30
}
  • 连接阶段-解析:虚拟机JVM将常量池的符号引用替换为直接引用的过程
  • 初始化initialiazation:程序员执行类中定义的Java程序代码,是执行<clinit>() 方法的过程。
    该方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
    虚拟机保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,知道活动线程执行<clinit>()方法完毕。(该机制保证某个类在内存中只有一个Class对象)
//直接使用类的静态属性也会导致类加载
public class ClassLoad03 {public static void main(String[] args) throws ClassNotFoundException {//分析//1. 加载B类,并生成 B的class对象//2. 连接 num = 0//3. 初始化阶段//    依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并/*clinit() {System.out.println("B 静态代码块被执行");//num = 300;num = 100;}合并: num = 100*///	  执行clinit()new B();//类加载System.out.println(B.num);//100, 如果直接使用类的静态属性,也会导致类的加载/*B 静态代码块被执B() 构造器被执行100 */}
}class B {static {System.out.println("B 静态代码块被执行");num = 300;}static int num = 100;public B() {//构造器System.out.println("B() 构造器被执行");}
}

※反射获取类的结构信息

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
构造函数:默认修饰符 是0,public是1。
在这里插入图片描述

访问属性
访问方法

反射相关类

在这里插入图片描述

//通过反射创建对象
//1 获取User类的Class对象
Class<?> userClass = Class.forName("com.hspedu.reflection.User");
//2.1 通过public的无参构造器创建实例
Object o = userClass.newInstance();
//2.2 通过public的有参构造器创建实例(先得到对应构造器,并传入实参)
Constructor<?> constructor = userClass.getConstructor(String.class);
Object o2 = constructor.newInstance("o2")
//2.3 通过菲public的有参构造器创建实例(先得到私有构造器,再传入实参)
Constructor<?> constructor3 = userClass.getDeclaredConstructor(int.class, String.class);
constructor3.setAccessible(true);//爆破:使用反射可以访问private构造器/方法/属性
Object user3 = constructor3.newInstance(100, "张三");

反射调用性能优化

Class类常用方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/792807.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跨境金融区块链服务平台

跨境金融服务是因企业及个人跨境经营、交易、投资、往来等活动而产生的资金使用、调拨、配置等需求&#xff0c;而提供的金融服务。近年来&#xff0c;随着我国经济的快速稳步增长和全球化经济一体化的不断深入发展&#xff0c;跨境金融业务增长迅速&#xff0c;监管也开始转化…

AcWing 731. 毕业旅行问题(每日一题)

原题链接&#xff1a;731. 毕业旅行问题 - AcWing题库 此题难度较大&#xff0c;是2019年字节跳动校招题&#xff0c;里面涉及位运算与状态压缩DP&#xff0c;不会的可以去学习&#xff0c;此题根据个人量力而行。 建议看一下y总的讲解&#xff1a;AcWing 731. 毕业旅行问题&…

初识MySQL(中篇)

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 目录 1.SQL语言 1.1 SQL语言组成部分 2.MySQL数据类型 2.1 数值类型 2.2 字符串类型 2.3 日期类型 3.创建数据表 3.1 创建数据表方法1 …

【A 类比赛】大学生学科竞赛智慧应用场景题目大全

智能应用的多彩场景&#xff1a;未来生活的无限可能 随着科技的飞速发展&#xff0c;智能应用已经渗透到我们生活的方方面面&#xff0c;它们不仅极大地提高了工作效率&#xff0c;也丰富了我们的生活体验。从家庭到工作场所&#xff0c;从城市到乡村&#xff0c;智能应用正在…

vLLM 部署大模型

1 介绍 vLLM 是来自 UC Berkeley 的 LMSYS 在 LLM 推理方面的最新工作&#xff08;没错就是搞出 Vicuna 的那个 group&#xff09;&#xff0c;最大亮点是采用 Paged Attention 技术&#xff0c;结合 Continuous Batching&#xff0c;极大地优化了 realtime 场景下的 LLM serv…

Mybitis根据Date查询,查询不到数据的一种情况

使用SimpleDateFormat创建Date对象时&#xff0c;调用SimpleDateFormat构造方法时格式要写为“yyyy-MM-dd”&#xff0c;如果写成“yyyy-mm-dd”会查询不到数据

Java基础学习: 格式化之 %d,%2d, %02d

在Java中&#xff0c;%d 是用于格式化整数的格式化符号。下面是对不同使用情况的解释&#xff1a; %d&#xff1a;表示将整数值按照默认格式化方式输出。 int number 5; System.out.printf("%d", number); // 输出&#xff1a;5%2d&#xff1a;表示将整数值按照至…

2024-HW --->SSRF

这不是马上准备就要护网了嘛&#xff0c;如火如荼的报名ing&#xff01;&#xff01;&#xff01;那么小编就来查缺补漏一下以前的web漏洞&#xff0c;也顺便去收录一波poc&#xff01;&#xff01;&#xff01;&#xff01; 今天讲的主人公呢就是SSRF&#xff0c;以前学的时候…

windows server 配置DNS

配置DNS为本机IPV4地址 安装DNS服务器&#xff08;默认即可&#xff09;

Qt学习路线推荐(超硬核)

Qt 是一个跨平台的 C图形用户界面应用程序开发框架&#xff0c;它具有强大的功能和丰富的工具&#xff0c;广泛应用于桌面应用程序、移动应用程序和嵌入式系统等领域。如果你对 Qt 感兴趣并想要学习它&#xff0c;以下是一份推荐的学习路线&#xff1a; 1.基础知识学习&#x…

【C++ STL排序容器】set 集合

文章目录 【 1. 基本原理 】【 2. set 的定义 】2.1 调用默认构造函数&#xff0c;创建空的 set 容器2.2 在创建 set 容器的同时&#xff0c;对其进行初始化2.3 拷贝构造的方式创建2.4 取已有 set 容器中的部分元素&#xff0c;来初始化新 set 容器2.5 修改排序规则的方式创建 …

Kotlin:for循环的几种示例

一、 打印 0 到 2 1.1 方式一&#xff1a;0 until 3 /*** 打印 0 到 2*/ fun print0To2M1(){for (inex in 0 until 3){// 不包含3print("$inex ")} }运行结果 1.2 方式二&#xff1a;inex in 0 …2 /*** 打印 0 到 2*/ fun print0To2M2(){for (inex in 0 ..2){//…

Go语言如何使用命令行程序

命令行程序也叫命令行实用程序或工具&#xff0c;它被设计在终端运行。 在图形用户界面面世前&#xff0c;与计算机交与通常是通过命令行进行的。当前&#xff0c;对程序员和系统管理员来说&#xff0c;命令行程序依然是一种流行而实用的与底层操作系统交互的方式。出于如下原因…

HarmonyOS NEXT应用开发之ForEach:循环渲染

ForEach接口基于数组类型数据来进行循环渲染&#xff0c;需要与容器组件配合使用&#xff0c;且接口返回的组件应当是允许包含在ForEach父容器组件中的子组件。例如&#xff0c;ListItem组件要求ForEach的父容器组件必须为 List组件 。 说明&#xff1a; 从API version 9开始&a…

Rust---复合数据类型之字符串与切片(1)

目录 字符串字符串与切片字符串切片字符串操作追加&#xff08;Push&#xff09;插入 (Insert)替换 (Replace) 字符串 Rust 在语言级别&#xff0c;只有一种字符串类型&#xff1a; str&#xff0c;它通常是以引用类型出现 &str。虽然语言级别只有上述的 str 类型&#xf…

C库函数详解(一)

库函数并不是C语言的一部分。它是由人们根据需要编制并提供用户使用的。每一种C编译系统都提供了一批库函数,不同的编译系统所提供的库函数的数目和函数名以及函数功能是不完全相同的。ANSIC标准提出了一批建议提供的标准库函数。它包括了目前多数C编译系统所提供的库函数,但也…

环形链表的约瑟夫问题

著名的 Josephus 问题&#xff1a; 据说著名犹太历史学家Josephus&#xff08;弗拉维奥约瑟夫斯&#xff09;有过以下的故事&#xff1a;在罗马人占领乔塔帕特后&#xff0c;39 个犹太人与Josephus及他的朋友躲到一个洞中&#xff0c;39个犹太人决定宁愿死也不要被敌人抓到&…

【哈希表专题】(1. 两数之和 面试题 01.02. 判定是否互为字符重排 217. 存在重复元素 219. 存在重复元素 II 49. 字母异位词分组)

文章目录 哈希表1. 两数之和面试题 01.02. 判定是否互为字符重排217. 存在重复元素219. 存在重复元素 II49. 字母异位词分组 哈希表 哈希表是什么&#xff1a;存储数据的容器 作用&#xff1a;快速查找某个元素。O(1) 当我们需要频繁的查找某一个数的时候&#xff0c;可以使…

LeetCode-Java:135.分发糖果

文章目录 题目解① 穷举法&#xff0c;用时3ms&#xff0c;超过26.93%②穷举法改进&#xff0c;用时2ms&#xff0c;超过97.78% 题目 n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。 你需要按照以下要求&#xff0c;给这些孩子分发糖果&#xff1a; 每个…

图像拼接——最小割准则提取拼接缝

一、最大流问题与Ford-Fulkerson算法介绍 二、最大流与最小割 显然,我们有对任意一个割,穿过该割的净流量上界就是该割的容量,即不可能超过割的容量。所以网络的最大流必然无法超过网络的最小割。最小割是指割的容量最小,最大流是指网络当中最大的净流量,简单的例子s是水龙…