day24_java的反射机制
反射
一、反射的概念
反射:加载类,反射出类的各个组成部分(类的成员:构造方法,属性,方法)
java反射机制:在运行状态中,对于任何一个类都能够知道这个类的所有属性和方法;对于任意一个对象,能够调用它的任意属性和方法;这种动态获取信息的方式就称为反射。
二、加载类???怎么加载
当程序要使用某个类时,如果这个类没有加载到内存中,则系统会通过加载,连接,初始化三个步骤来实现对这个类的初始化。
-
加载:
将class(字节码)文件读取到内存中,并为之创建一个Class对象
任何类被使用时都会被创建一个Class对象(注:一个类只有一个Class对象)
-
连接:
- 验证:是否有正确的内部结构,并和其它协调一致
- 准备:负责为类的静态成员分配内存,并设置默认初始化
- 解析:将类的二进制数据中的符号引用替换成直接引用
-
初始化:
该阶段主要是为类的类变量初始化值的,初始化有两种方式:
- 在声明类变量时,直接给变量赋值
- 在静态初始化块为类变量赋值
(一)类加载的时机
- 创建类的实例
- 访问类的静态成员或给静态变量赋值
- 调用类的吧静态方法
- 初始化某个类的子类
- java命令运行某个类(如:java HelloWorld)
- 使用反射的方法(将某个类加载到类加载区)强制创建某个类的Class对象
(二)类加载器
负责将class 文件加载到内存中,并为之创建一个Class对象,如果了解类加载器的机制,可以的更好的理解程序的运行
类加载器的组成:
-
根类加载器: bootstrap classLoader
也被称为引导类加载类,负责Java核心类的加载
比如: System, String 等,在 JDK 中的JRE 中 lib 中的 rt.jar文件中
-
扩展类加载器: extension classLoader
负责jre的扩展目录中的jar的加载
-
系统类加载器: System classLoader
负责在JVM启动时加载来自java命令的class文件
三、反射类的成员
(一)获取Class对象的方式
// 先创建了一个Person类
public class Person {private String name;int age;public String address;public Person() {}private Person(String name){this.name = name;}Person(String name, int age) {this.name = name;this.age = age;}public Person(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}public void show(){System.out.println("show");}public void method(String s){System.out.println("method"+s);}public String getString(String s,String m){return s+"----"+m;}private void function(){System.out.println("function");}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}
}
// 获取Person类的Class对象
// 方法1:
Person person = new Person();
Class c = person.getClass();
// 方法2:
Class c2 = Person.class;
// 方法3:
Class c3 = Class.forName("com.gxa.demo1.Person");
// c=c2=c3:因为一个类的Class对象只有一个
注:在开发中我们常使用第三种方式去做反射,因为第三种传入的是个字符串而不是具体的类名,这样的话就可以把这个值方法配置文件中去,方便修改。
(二)获取类加载器
a: 得到类的Class对象
Class c = Class.forName("com.gxa.demo1.Person");
b: 获取类的加载器
ClassLoader classLoader = c.getClassLoader();
-
使用类加载器加载其它的文件
// 得到Class对象 Class c = Class.forName("com.gxa.demo1.Person"); // 获取类加载器对象 ClassLoader classLoader = c.getClassLoader(); // 类加载器加载其它文件(加入我的src目录下面有一个jdbc.properties文件) InputStream in = classLoader.getResourceAsStream("jdbc.properties");注:如果找不到文件则会返回null给输入流
(三)反射类的构造方法
-
public Constructor<T> getConstructor(类<?>... parameterTypes):返回一个Constructor对象,返回的是public修饰的构造方法;如果不写参数则返回无参的构造函数对象;如果构造方法不是公共的将会报异常:NoSuchMethodExceptionClass c = Class.forName("com.gxa.demo1.Person"); // 返回公共的无参构造,如果无参构造不是public修饰的将会报错 Constructor constructor = c.getConstructor(); System.out.println(constructor); // 有参数传入:传入的参数是数据类型类的Class对象;下面是获取一个参数为String类型的构造方法对象 Constructor constructor = c.getConstructor(String.class); System.out.println(constructor); -
public Constructor<?>[] getConstructors():返回一个public修饰的构造方法的Constructor对象的数组Constructor[] constructors = c.getConstructors(); // 返回的构造方法都是public修饰的 System.out.println(constructors); -
public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes):返回一个Constructor对象,不传参数返回无参的构造方法(没有修饰符的限制),如果构造方法不存在将报异常:NoSuchMethodException// 获取无参的构造方法 Constructor declaredConstructor = c.getDeclaredConstructor(); System.out.println(declaredConstructor); -
public Constructor<?>[] getDeclaredConstructors():返回所有构造方法的Constructor对象的数组// 获取所有方法 Constructor[] declaredConstructors = c.getDeclaredConstructors(); System.out.println(declaredConstructors);
1、通过Constructor对象创建实例
// 获取Class对象
Class c = Person.class;
// 获取Person类的无参构造
Constructor declaredConstructor = c.getDeclaredConstructor();
// 通过构造方法对象创建一个Person类的实例对象
Object obj = declaredConstructor.newInstance();
System.out.println(obj);
注:如果获取的构造方法对象是一个非私有的,那么将会报IllegalAccessException异常;
解决方案:
在Constructor类里面有一个方法叫作:public void setAccessible(boolean flag)的方法,将此对象的accessible标志设置为指示的布尔值。 true的值表示反射对象应该在使用时跳过java的语法检查。
// 获取Class对象
Class c = Person.class;
// 获取Person类的无参构造
Constructor declaredConstructor = c.getDeclaredConstructor();
// 设置constructor对象的访问权限
declaredConstructor.setAccessible(true);
// 通过构造方法对象创建一个Person类的实例对象
Object obj = declaredConstructor.newInstance();
System.out.println(obj);// 通过有参构造方法创建类的实例
Class c = Person.class;Constructor declaredConstructor = c.getDeclaredConstructor(String.class);declaredConstructor.setAccessible(true);Object obj = declaredConstructor.newInstance("张三");
System.out.println(obj);
(四)反射类的属性
与获取构造方法对象的获取方法相似:
-
public Field getField(String name):返回一个Field对象,它反映此表示的类或接口的指定公共成员字段类对象。Class c = Person.class; Field addressField = c.getField("address"); System.out.println(addressField);
注:在使用getField方法是如果传的name为不存在的属性或非公共属性将会报异常:NoSuchFieldException
-
public Field[] getFields():返回包含一个数组Field对象反射由此表示的类或接口的所有可访问的公共字段类对象。// 获取该类公共属性的field对象的数组 Field[] fields = c.getFields(); -
public Field getDeclaredField(String name):返回一个Field对象,它反映此表示的类或接口的指定字段类对象。Field name = c.getDeclaredField("name"); -
public Field[] getDeclaredFields():返回的数组Field对象反映此表示的类或接口声明的所有字段类对象。获取所有属性的field对象集合 Field[] fields = c.getDeclaredFields();
1、通过反射来给Person的对象赋值
// 没有对象就没有属性
// 要使用属性,必须 要有对象
// 1、反射一个无参的构造方法的Constructor对象
Constructor constructor = c.getDeclaredConstructor();
// 2、创建对应的对象
Object obj = constructor.newInstance();
// 3、反射Person类的属性对象
Field namefield = c.getDeclaredField("name");
Field agefield = c.getDeclaredField("age");
Field addressfield = c.getDeclaredField("address");
// 4、给对象实例赋值
namefield.setAccessible(true); // 设置私有属性的访问权限
namefield.set(obj,"张三");
agefield.set(obj,18);
addressfield.set(obj,"成都");
System.out.println(obj);
(五)反射类的方法
-
public 方法 getDeclaredMethod(String name,类<?>... parameterTypes):返回一个方法对象,它反映此表示的类或接口的指定声明的方法类对象。 -
public 方法[] getDeclaredMethods():返回包含一个数组方法对象反射的类或接口的所有声明的方法,通过此表示类对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。 -
public 方法 getMethod(String name,类<?>... parameterTypes):返回一个方法对象,它反映此表示的类或接口的指定公共成员方法类对象。 -
public 方法[] getMethods():返回包含一个数组方法对象反射由此表示的类或接口的所有公共方法类对象,包括那些由类或接口和那些从超类和超接口继承的声明。// 1、获取Class对象 Person person = new Person(); Class aClass = person.getClass(); // 2、获取Person的方法Method对象 Class对象.getDeclaredMethod("方法名",数据类型的Class对象); Method method = aClass.getDeclaredMethod("method", String.class); // invoke是Method类中的方法:表示调用某个具体对象的方法 Method对象.invoke(类的实例对象,参数...); // 通过Method对象调用person对象的method方法,为了防止权限不够(方法为私有的)最好使用setAccessible(true)来跳过java的代码检查 method.setAccessible(true); method.invoke(person,"反射调用了method方法");案例:
在ArrayList 对象中添加一个字符串;
我们知道指定了ArrayList中参数的类型再传入其他类型的话java会报错,那么这个时候我们就可以通过反射的方式去获取ArrayList类中的add方法给ArrayList的对象赋值,因为ArrayList类的add方法传入的参数是一个泛型而不是具体的类型,所以我们可以添加任意数据:
// 1、创建一个ArrayList<Integer>对象 ArrayList<Integer> list = new ArrayList<>(); // 2、通过反射的方式获取ArrayList的Class对象 Class listClass = list.getClass(); // 3、通过Class对象反射add方法 Method listAdd = listClass.getDeclaredMethod("add",Object.class); // 4、通过ArrayList类的add方法给ArrayList<Integer>实例对象添加值// 4.1、为了防止访问的权限不够加上setAccessible方法跳过java代码检查 listAdd.setAccessible(true);// 4.2、添加值 listAdd.invoke(list,"我在Integer类型的集合里添加了一个字符串"); // 5、打印输出list集合 System.out.println(list);
面试题
面试题
第一题:JDBC操作数据库的步骤 ?
1)注册数据库驱动。
2)建立数据库连接。
3)获取statemen对象。
4)执行SQL语句。
5)返回结果(如果是查询操作有结果集:处理结果集)。
6)(释放资源)关闭数据库连接
第二题:JDBC中的Statement 和PreparedStatement,CallableStatement的区别?
1)PreparedStatement是预编译的SQL语句,效率高于Statement。
2)PreparedStatement支持“?”操作符,相对于Statement更加灵活。
3)PreparedStatement可以防止SQL注入,安全性高于Statement。
4)CallableStatement适用于执行存储过程。
第三题:execute,executeQuery,executeUpdate的区别是什么?
· Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpdateCount()方法来获取更新的记录条数。
· Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery来执行查询语句,这样的话如果传进来的是insert或者update语句的话,它会抛出错误信息为 “executeQuery method can not be used for update”的java.util.SQLException。
· Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回DDL语句。返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。
· 只有当你不确定是什么语句的时候才应该使用execute()方法,否则应该使用executeQuery或者executeUpdate方法。
第四题:PreparedStatement的缺点是什么,怎么解决这个问题?
PreparedStatement的一个缺点是,我们不能直接用它来执行in条件语句;需要执行IN条件语句的话,下面有一些解决方案:
1)分别进行单条查询——这样做性能很差,不推荐。
2)使用存储过程——这取决于数据库的实现,不是所有数据库都支持。
3)动态生成PreparedStatement——这是个好办法,但是不能享受PreparedStatement的缓存带来的好处了。
4)在PreparedStatement查询中使用NULL值——如果你知道输入变量的最大个数的话,这是个不错的办法,扩展一下还可以支持无限参数。
第五题:JDBC的ResultSet是什么?
在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。
ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。
默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet。
当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。
可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。
相关文章:
day24_java的反射机制
反射 一、反射的概念 反射:加载类,反射出类的各个组成部分(类的成员:构造方法,属性,方法) java反射机制:在运行状态中,对于任何一个类都能够知道这个类的所有属性和方…...
VUE学习二、创建一个前端项目
1.创建一个vue项目 使用命令 vue ui启动vue脚手架 vue ui 等待项目创建好 可以来任务栏启动项目 参数那里可以设置启动端口等参数 启动成功 成功访问 2. 用webstorm 打开项目 脚手架页面可安装基本依赖 比如路由 使用ws打开项目 启动项目 npm run serve 3.修改启动…...
「红队笔记」靶机精讲:Prime1 - 信息收集和分析能力的试炼
「红队笔记」靶机精讲:Prime1 - 信息收集和分析能力的试炼 本文是作者在观看 B 站《红队笔记》后做的一些笔记及相关知识的补充。学渗透特别推荐大家去看。如有侵权,请联系作者,作者看到后会第一时间删除。 靶机精讲之Prime1,vu…...
JVM虚拟机系统性学习-对象的创建流程及对象的访问定位
对象的创建流程与内存分配 对象创建流程如下: Java 中新创建的对象如何分配空间呢? new 的对象先放 Eden 区(如果是大对象,直接放入老年代)当 Eden 区满了之后,程序还需要创建对象,则垃圾回收…...
perf与火焰图-性能分析工具
参考链接 perf性能分析工具使用分享 如何读懂火焰图?-阮一峰 perf基本用法-record,report-知乎 火焰图抓取 准备: centos安装perf工具 dnf install perf下载火焰图解析代码 git clone https://github.com/brendangregg/FlameGraph.git抓取指定进程…...
UniGui使用CSSUniTreeMenu滚动条
有些人反应UniTreeMenu当菜单项目比较多的时候会超出但是没有出滚动条,只需要添加如下CSS 老规矩,unitreemeu的layout的componentcls里添加bbtreemenu,然后在css里添加 .bbtreemenu .x-box-item{ overflow-y: auto; } 然后当内容超出后就会…...
Spring框架中的五种常用设计模式
1、单例模式 Spring 的 Bean 默认是单例模式,通过 Spring 容器管理 Bean 的⽣命周期,保证每个 Bean 只被 创建⼀次,并在整个应⽤程序中重用。 2.工厂模式 Spring 使⽤⼯⼚模式通过 BeanFactory 和 ApplicationContext 创建并管理 Bean 对象…...
华纳云:docker启动报错的原因和解决方法
Docker 启动报错可能由多种原因引起。以下是一些建议,可用于解决 Docker 启动问题: 查看 Docker 日志: 查看 Docker 的日志可以提供更多的详细信息,有助于定位问题。 sudo journalctl -xe | grep docker 或者查看 Docker 服务的详…...
代码规范及开发工具
代码规范及开发工具: 前端(vscode、idea): JavaScript规范: 1. 谷歌开源项目风格指南:JavaScript 、TypeScript篇 https://zh-google-styleguide.readthedocs.io/en/latest/google-typescript-…...
证件照制作小程序源代码
17638103951(同v)...
自治调优!人大金仓解放DBA双手
数据库系统的性能是确保整个应用系统高效运转的关键因素,因此数据库性能调优工作至关重要。KingbaseES通过将人工调优过程内化为数据库内核,成功实现了自治调优。这种创新的调优方案为DBA提供了更高效且准确的性能调优途径,同时也显著降低了数…...
深度学习环境配置------windows系统(GPU)------Pytorch
深度学习环境配置------windows系统(GPU)------Pytorch 准备工作明确操作系统明确显卡系列 CUDA和Cudnn下载与安装1.下载2.安装 环境配置过程1.安装Anacoda2.配置环境1)创建一个新的虚拟环境2)pytorch相关库的安装 2.安装VScode1&…...
el-menu标题过长显示不全问题处理
项目基于vue-element-admin 问题 期望 处理方式 \src\layout\components\Sidebar\index.vue 文件后添加CSS <style scped> /* 侧栏导航菜单经典 文字超长溢出问题 CSS折行 */ .el-submenu__title {display: flex;align-items: center; } .el-submenu__title span {white-…...
微信游戏开发:连接社交与娱乐的创新之路
在移动互联网时代,微信已经成为了人们日常生活中不可或缺的社交工具。而微信游戏,作为在这一平台上崛起的新兴产业,不仅给用户提供了更多娱乐选择,也为开发者们创造了独特的机遇。本文将探讨微信游戏开发的关键步骤、技术要点以及…...
1688一件采购实现指南:含代码实现采购流程
一、引言 1688是中国最大的B2B电子商务平台之一,提供了丰富的商品信息和采购服务。一键采购是1688平台的一项便捷功能,可以帮助用户快速完成采购流程,提高采购效率。本文将详细介绍如何使用1688一键采购功能,并通过代码示例演示如…...
div中一个图片怎么铺满整个div而且不超出div按比例铺满div
重要信息: background-size:cover或者background-size:contain;属性 设置图片不重复: background-repeat:no-repeat; 设置字体在div中间:...
云原生之深入解析Kubernetes的架构及特性
一、kubernetes 架构 从宏观上来看 kubernetes 的整体架构,包括 Master、Node 以及 Etcd。Master 即主节点,负责控制整个 kubernetes 集群,它包括 Api Server、Scheduler、Controller 等组成部分。它们都需要和 Etcd 进行交互以存储数据&…...
分布工具类的定义与实现及测试。
package d5.util;public class PageUtil {private int pageSize;//一页有多少条private int currIndex;//当前是第几页private int totalCount;//共有多少条记录 谁给我? 逻辑层的 getTotalCountprivate int totalPage;//共有多少页 private int start;//显时时开始…...
如何在忘记密码的情况下恢复解锁 iPhone
您忘记了 iPhone 密码吗?Apple 官方通常建议将 iPhone 恢复至出厂设置以将其删除。这种修复很不方便,甚至可能比问题本身更麻烦。 如果您也经历过同样的情况,并且想知道忘记了 iPhone 密码并且不想恢复它该怎么办,我们的终极指南…...
通过compileall库将python文件编译为pyc文件
文章目录 什么是 .pyc 文件将 .py 文件编译为 .pyc 文件编译单个文件编译多个文件 在实际开发中,有时候需要将产品(以.py文件为例)发布到外部环境,但我们并不想显式地让别人看到我们的源码,此时就需要对源码进行加密保…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
