每天学一点之类的加载和反射

news2024/11/14 20:38:13

类加载

类在内存中的生命周期:加载–>使用–>卸载
类的加载又分为三个阶段:

(1)加载:load

指将类型的clas字节码数据读入内存。

  • 通过类的全名,获取类的二进制数据流。
  • 解析类的二进制数据流为方法区内的数据结构(Java类模型)

(2)连接:link

①验证:校验合法性等

  • 格式验证:是否以魔数0XCAFEBABE开头,数据中每一个项是否都拥有正确的长度等。

  • 语义检查:Java虚拟机会进行字节码的语义检查,但凡在语义上不符合规范的,虚拟机也不会给予验证通过。比如:
    是否所有的类都有父类的存在(在Java里,除了Object外,其他类都应该有父类)
    是否一些被定义为final的方法或者类被重写或继承了
    非抽象类是否实现了所有抽象方法或者接口方法

②准备:准备对应的内存

  • 准备对应的内存(方法区),创建Class对象,为类变量赋默认值,为静态常量赋初始值。

③解析:将类、接口、字段和方法的符号引用转为直接引用

  • 符号引用就是一些字面量的引用,和虚拟机的内部数据结构和和内存布局无关。比较容易理解的就是在Class类文件中,通过常量池进行了大量的符号引用。但是在程序实际运行时,只有符号引用是不够的,系统需要明确知道数据的位置。

(3)初始化:initialize

1、哪些操作会导致类的初始化?

(1)运行主方法所在的类,要先完成类初始化,再执行main方法

(2)第一次使用某个类型就是在new它的对象,此时这个类没有初始化的话,先完成类初始化再做实例初始化

(3)调用某个类的静态成员(类变量和类方法),此时这个类没有初始化的话,先完成类初始化

(4)子类初始化时,发现它的父类还没有初始化的话,那么先初始化父类

(5)通过反射操作某个类时,如果这个类没有初始化,也会导致该类先初始化

类初始化执行的是(),该方法由(1)类变量的显式赋值代码(2)静态代码块中的代码构成

详解类的初始化和实例初始化的过程

2、哪些使用类的操作,但是不会导致类的初始化?

(1)使用某个类的静态的常量(static final)

(2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化,即只有声明静态成员的类才会初始化

(3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化

3、类加载器

1、类加载器分为:
(1)引导类加载器(Bootstrap Classloader)又称为根类加载器

它负责加载jre/rt.jar核心库
它本身不是Java代码实现的,也不是ClassLoader的子类,获取它的对象时往往返回null

(2)扩展类加载器(Extension ClassLoader)

它负责加载jre/lib/ext扩展库
它是ClassLoader的子类

(3)应用程序类加载器(Application Classloader)

它负责加载项目的classpath路径下的类
它是ClassLoader的子类

(4)自定义类加载器

当你的程序需要加载“特定”目录下的类,可以自定义类加载器;
当你的程序的字节码文件需要加密时,那么往往会提供一个自定义类加载器对其进行解码
后面会见到的自定义类加载器:tomcat中

2、Java系统类加载器的双亲委托模式(parents delegate)

在这里插入图片描述
简单描述:

下一级的类加载器,如果接到任务时,会先搜索是否加载过,如果没有,会先把任务往上传,如果都没有加载过,一直到根加载器,如果根加载器在它负责的路径下没有找到,会往回传,如果一路回传到最后一级都没有找到,那么会报ClassNotFoundException或NoClassDefError,如果在某一级找到了,就直接返回Class对象。

优势

1.采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关系可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。
2.安全,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改。

应用程序类加载器 把 扩展类加载器视为父加载器,
扩展类加载器 把 引导类加载器视为父加载器。

4、类的卸载

在这里插入图片描述

java.lang.Class类

Java反射机制是 : 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
Class对象是反射的根源。

1、哪些类型可以获取Class对象

所有Java类型

//(1)基本数据类型和void
例如:int.class
	 void.class
//(2)类和接口
例如:String.class
	Comparable.class
//(3)枚举
例如:ElementType.class
//(4)注解
例如:Override.class
//(5)数组
例如:int[].class

2、获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

反射的应用

获取类型的详细信息

//1、先得到某个类型的Class对象
		Class clazz = String.class;
		//比喻clazz好比是镜子中的影子
		
		//2、获取类信息
		//(1)获取包对象,即所有java的包,都是Package的对象
		Package pkg = clazz.getPackage();
		System.out.println("包名:" + pkg.getName());
		
		//(2)获取修饰符
		//其实修饰符是Modifier,里面有很多常量值
		/*
		 * 0x是十六进制
		 * PUBLIC           = 0x00000001;  1    1
		 * PRIVATE          = 0x00000002;  2	10
		 * PROTECTED        = 0x00000004;  4	100
		 * STATIC           = 0x00000008;  8	1000
		 * FINAL            = 0x00000010;  16	10000
		 * ...
		 * 
		 * 设计的理念,就是用二进制的某一位是1,来代表一种修饰符,整个二进制中只有一位是1,其余都是0
		 * 
		 * mod = 17          0x00000011
		 * if ((mod & PUBLIC) != 0)  说明修饰符中有public
		 * if ((mod & FINAL) != 0)   说明修饰符中有final
		 */
		int mod = clazz.getModifiers();
		System.out.println(Modifier.toString(mod));
		
		//(3)类型名
		String name = clazz.getName();
		System.out.println(name);
		
		//(4)父类,父类也有父类对应的Class对象
		Class superclass = clazz.getSuperclass();
		System.out.println(superclass);
		
		//(5)父接口们
		Class[] interfaces = clazz.getInterfaces();
		for (Class class1 : interfaces) {
			System.out.println(class1);
		}

//获取构造器、方法和属性

       Class<Student> clazz = Student.class;
        //构造器不参与继承,只能获取本类的构造器。
        for (Constructor<?> constructor : clazz.getConstructors()) {//获取本类所有公共的构造器
            System.out.println(constructor);
        }
        Constructor<Student> constructor = clazz.getConstructor(String.class, Integer.class, Double.class);//获取指定构造器
        System.out.println("constructor = " + constructor);
        Constructor<?>[] declaredClasses = clazz.getDeclaredConstructors();//获取本类所有的构造器包含私有的
        for (Constructor<?> declaredClass : declaredClasses) {
            System.out.println("declaredClass = " + declaredClass);
        }
        Constructor<Student> declaredConstructor = clazz.getDeclaredConstructor(String.class, Double.class);
        System.out.println("declaredConstructor = " + declaredConstructor);//获取指定构造器包含私有的
        //使用私有构造器时要先暴力反射
        declaredConstructor.setAccessible(true);
        Student student = declaredConstructor.newInstance("张三", 99.6);
        System.out.println("student = " + student);

        for (Field field : clazz.getFields()) { //获取所有公共的成员变量包含继承的公共成员变量
            System.out.println("field = " + field);
        }
        Field score = clazz.getField("score");//获取指定公共的成员变量包含继承的公共成员变量
        System.out.println("score = " + score);
        //getDeclaredField、getDeclaredFields都只能获取本类的成员变量。
        Field name = clazz.getDeclaredField("name");//获取指定的成员变量包含私有的
        //使用私有的成员变量时要先暴力反射
        name.setAccessible(true);
        name.set(student, "小明");//给指定对象成员变量赋值
        Object o = name.get(student);//返回name属性值,没有时则返回null
        System.out.println("o = " + o);
        System.out.println("student = " + student);
        System.out.println("name = " + name);
        for (Field declaredField : clazz.getDeclaredFields()) {//获取所有成员变量
            System.out.println("declaredField = " + declaredField);
        }
        for (Method method : clazz.getMethods()) {//获取本类及父类所有的公共方法(包含间接继承的父类(object)公共方法)
            System.out.println("method = " + method);
        }
        Method setName = clazz.getMethod("setName", String.class);//获取本类及父类指定的公共方法(包含间接继承的父类(object)公共方法)
        Object stu = setName.invoke(student, "李四");//看此方法有无返回值类型,如果没有就返回null,反射在此处相当于为所有方法返回值做准备
        System.out.println("stu = " + stu);//null
        for (Method declaredMethod : clazz.getDeclaredMethods()) {//获取本类所有的方法(包含私有方法)
            System.out.println("declaredMethod = " + declaredMethod);
        }
        Method say = clazz.getDeclaredMethod("say", String.class, String.class);//获取本类指定的私有方法
        //使用私有的方法时先暴力反射
        say.setAccessible(true);
        say.invoke(student,"张三","hello");//相当于对象调方法传参数

创建任意引用类型的对象

两种方式:

1、直接通过Class对象来实例化(要求必须有无参构造)

2、通过获取构造器对象来进行实例化

方式一的步骤:

(1)获取该类型的Class对象(2)创建对象

方式二的步骤:

(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象

如果构造器的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

操作任意类型的属性

(1)获取该类型的Class对象
Class clazz = Class.forName(“com.atguigu.bean.User”);

(2)获取属性对象
Field field = clazz.getDeclaredField(“username”);

(3)设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象
Object obj = clazz.newInstance();

(4)设置属性值

field.set(obj,“chai”);
(5)获取属性值
Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

调用任意类型的方法

(1)获取该类型的Class对象
Class clazz = Class.forName(“com.atguigu.service.UserService”);
(2)获取方法对象
Method method = clazz.getDeclaredMethod(“login”,String.class,String.class);
(3)创建实例对象
Object obj = clazz.newInstance();
(4)调用方法
Object result = method.invoke(obj,“chai”,"123);

如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)

如果方法是静态方法,实例对象也可以省略,用null代替

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

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

相关文章

【Go自学第二节】Go中的数组与切片

在Golang中&#xff0c;数组属于聚合类型&#xff0c;而切片属于引用类型。其实切片的底层逻辑就是用数组实现的&#xff0c;所以我们首先需要了解数组。 一、数组 Array 数组是具有相同唯一类型的一组已编号且长度固定的数据项序列&#xff0c;这种类型可以是任意的原始类型例…

Unity 3D GUI教程||OnGUI TextArea 控件||OnGUI ScrollView 控件

OnGUI TextArea 控件 Unity 3D TextArea 控件用于创建一个多行的文本编辑区。用户可以在多行文本编辑区编辑文本内容。 该控件可以对超出控件宽度的文本内容实现换行操作。 TextArea 控件同样会将当前文本编辑区中的文本内容以字符串形式返回。 开发人员可以通过创建 Strin…

Astra pro相机使用说明

奥比中光的Astra pro这款相机&#xff0c;目前官网已经搜不到相关信息&#xff0c;应该是停产了。但是很多机器人设备上或者淘宝上还能买到。使用起来经常会出现不同的问题。问题1&#xff1a; 这款相机据网友描述&#xff0c;就是乐视相机LeTMC-520&#xff0c;换了外壳&#…

easy-jenkins部署vue和jar

easy-jenkins是一款对vue和jar的部署工具&#xff0c;操作简单&#xff0c;实行一键部署&#xff0c;内部结构采用流水线形式架构&#xff0c;每次部署&#xff0c;时时提供部署过程&#xff0c;部署记录&#xff0c;界面友好简洁&#xff0c;使用方便&#xff0c;符合用户常规…

tmall.item.update.schema.get( 天猫编辑商品规则获取 )

&#xffe5;开放平台免费API必须用户授权 Schema方式编辑天猫商品时&#xff0c;编辑商品规则获取 公共参数 请求地址: HTTP地址 http://gw.api.taobao.com/router/rest 公共请求参数: 公共响应参数: 点击获取key和secret 请求示例 TaobaoClient client new DefaultTaobao…

macos版m1安装 mongodb 记录,macos m1pro homebrew 方式安装 mongodb记录

目录先决条件 Homebrew检查 homebrew安装 homebrew安装 mongoDB安装流程启动方式常见问题先决条件 Homebrew 检查 homebrew 已安装跳过 检查是否安装 homebrew 指令&#xff0c;没安装的先安装这个 brew --version 安装 homebrew 自行查看另一片博文macos 安装 Homebrew …

【SpringCloud】SpringCloud原理之Gateway网关

目录前言SpringCloud Gatewy网关一.网关功能和工作原理二.网关的类型三.搭建网关四.路由断言工厂(Route Predicate Factory)五.路由过滤器(属于GatewayFilter)六.DefaultFilter过滤器(属于GatewayFilter)七.全局过滤器(GlobalFilter)八.过滤器执行顺序九.Gateway解决跨域问题前…

socket编程-TCP各函数及其用法

socket编程-TCP socket主要类型 流套接字&#xff08;SOCK_STREAM&#xff09; 流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复送&#xff0c;并按顺序接收。流套接字之所以能够实现可靠的数据服务&#xff0c;原因在于其使用了传输…

react框架基础入门

前端三大框架&#xff1a;angularvue —-2||3react区别&#xff1a;vue国内框架 封装较完成。全程使用封装的api来完成。react国外技术框架—-偏向于底层js实现。没有的大量的封装。需要使用js手动实现。react需求在不断增大。必会框架。官网https://react.docschina.org/ 中…

一文搞懂Linux时区设置、自定义时区文件

概念介绍 常说的 Linux 系统时钟有两个 一个是硬件时钟&#xff08;RTC&#xff09;&#xff0c;即BIOS时间&#xff0c;一般保存的是 GMT0 时间&#xff0c;没时区、夏令时的概念 一个是当地时钟&#xff08;LTC&#xff09;&#xff0c;即我们日常经常看到的时间&#xff0…

elasticsearch 分布式搜索引擎2

1.DSL查询文档 elasticsearch的查询依然是基于JSON风格的DSL来实现的。 1.1.DSL查询分类 Elasticsearch提供了基于JSON的DSL&#xff08;Domain Specific Language&#xff09;来定义查询。常见的查询类型包括&#xff1a; 查询所有&#xff1a;查询出所有数据&#xff0c;一…

手把手带你玩转Linux

今天这篇文章带你走进Linux世界的同时,带你手把手玩转Linux,加深对Linux系统的认识。 一、搞好Linux工作必须得不断折腾,说白了,只是动手力量必须强。我在初学Linux的那片,家中三台计算机,我在上边总是反反复复的进行着重装、网络ghost、双系统安装等的尝试。有很长一段时间里,…

CSS 之 background-clip 和 background-origin 属性

一、background-clip&#xff08;背景的绘制区域&#xff09; 1、纯色背景 该属性规定了背景的绘制区域&#xff0c;属性值有三种&#xff1a;border-box&#xff08;覆盖到边框区域&#xff09;、padding-box&#xff08;覆盖到padding区域&#xff0c;不包含border&#xf…

数据库学习笔记(4)——SQL语言之DQL

复杂分组查询举例 子查询&#xff1a;把select查询结果当作数据使用时&#xff0c;这种结构就是子查询 子查询练习 -- 子查询练习&#xff1a;查询学生成绩在70分以上的学生学号和姓名 select stu_id as id, stu_name as 姓名 from tb_student where stu_id in (select cc_sid…

Forter 对支付服务商应对欺诈的四个建议和Gartner的两个关键结论

Gartner新版2023年度《线上欺诈检测市场指南》发布恰逢其时&#xff0d;企业正面临来自专业黑产和欺诈者与日俱增的压力。而在2023年&#xff0c;许多商户将调整反欺诈策略&#xff0c;对拒付率和转化率进行更严格的监测&#xff0c;以最大限度减少损失并增加营收。以下是Gartn…

工作记录:bi重构

2023.3.8&#xff0c;我在组内进行工作汇报。内容记录如下&#xff1a; 本次重构的特点 改动大影响后续开发 所以有必要进行工作汇报&#xff0c;让组内同事了解代码的改动与现状。 为什么要重构代码&#xff1f; 正在开发的数据报告模块包含大量 widget 功能&#xff0c;…

量子计算(8)pyqpanda编程3测量操作

作为一名高产博主&#xff0c;小编我一天不写文章就浑身难受&#xff0c;这不&#xff0c;一闲下来就来给大家科普量子计算编程操作了。 今天我们要来探讨“测量操作”&#xff0c;众所周知&#xff0c;薛定谔的猫是一种既死又活的状态&#xff0c;很多人认为&#xff0c;猫是死…

数据分析介绍,让你更了解数据分析

同学们好&#xff01; 第一次接触互联网行业吗&#xff1f;没有关系&#xff0c;看完这篇介绍让你了解到底什么是数据分析&#xff1f;并对它强大的功能所吸引。希望你能耐心的看完&#xff0c;了解更多的行业信息&#xff01; 1、是不是不知道什么是数据分析&#xff1f; 定…

14.卷积神经网络中的不变性

欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; 文章目录1.问题介绍2.DCNN的Invariance3.后记参考资料1.问题介绍 最近看的2015年前后的几篇语义分割网络中反复提到了一个点,深度卷积神经网络的内置不变性。 2014年11月发表的Fully Conv…

线程池的线程是如何复用的

前言 进程和线程的关系相信大家都知道&#xff0c;这里我就不做过多的解释了&#xff0c;既然一个进程是由多个线程组成的&#xff0c;那么线程池又是由若干个线程队列组成的&#xff0c;在并发量比较高的情景下&#xff0c;我们通常会去创建线程池就执行任务&#xff0c;而不…