Java基础---String str=new String(“tang“)创建了几个对象

news2024/10/5 15:24:48

目录

典型回答

常量池基本概念

字符串常量池的结构

再看字面量和运行时常量池

intern

还是创建了几个对象

intern的正确用法


  • 典型回答

  • 创建的对象数应该是1个或者2个
  • 如果常量池中存在,则直接new一个对象
  • 如果常量池不存在,则在常量池中创建一个对象,也在堆中创建一个对象
  • 首先要清楚什么是对象?
  • Java是一种面向对象的语言,而Java对象在JVM中的存储也是有一定的结构的,在HotSpot虚拟机中,存储的形式就是oop-klass model,即Java对象模型
  • 在Java代码中,使用new创建一个对象的时候,JVM会创建一个instanceOopDesc对象,这个对象中包含了两部分信息,对象头以及元数据
  • 对象头中有一些运行时数据,其中就包括和多线程相关的锁的信息
  • 元数据其实维护的是指针,指向的是对象所属的类的instanceKlass
  • 这才叫对象
  • 其他的,一概都不叫对象
  • 那么不管怎么样,一次new的过程,都会在堆上创建一个对象,那么就是起码有一个对象了
  • 至于另外一个对象,到底有没有要看具体情况了
  • 另外这一个对象就是常量池中的字符串常量,这个字符串其实是类编译阶段就进到Class常量池的,那么当这个类第一次被ClassLoader加载的时候,会从Class常量池进入到运行时常量池
  • 在运行时常量池中,也并不是会立刻被解析成对象,而是会先以JVM_CONSTANT_UnresolveString_info的形式驻留在常量池
  • 在后面,该引用第一次被LDC指令执行到的时候,就尝试在堆上创建字符串对象,并将对象的引用驻留在字符串常量池中
  • 通过看上面的过程,也能发现,这个过程的触发条件是没办法决定的,问题的题干中也没提到
  • 有可能执行这段代码的时候是第一次LDC指令执行,也许在前面就执行过了
  • 所以,如果是第一次执行,那么就是会同时创建两个对象
  • 一个字符串常量引用指向的对象,一个我们new出来的对象
  • 如果不是第一次执行,那么就只会创建我们自己new出来的对象
  • 至于有人说什么在字符串池内还有在栈上还有一个引用对象,引用就是引用;别往对象上面扯
  • 常量池基本概念

  • 下面是基于jdk8版本进行说明:
  • class 文件常量池:
    • 在 class 文件中保存了一份常量池(Constant Pool),主要存储编译时确定的数据,包括代码中的字面量(literal)和符号引用
  • 运行时常量池:
    • 位于方法区中,全局共享,class 文件常量池中的内容会在类加载后存放到方法区的运行时常量池中;除此之外,在运行期间可以将新的变量放入运行时常量池中,相对 class 文件常量池而言运行时常量池更具备动态性
  • 字符串常量池:
    • 位于堆中,全局共享,这里可以先粗略的认为它存储的是 String 对象的直接引用,而不是直接存放的对象,具体的实例对象是在堆中存放
  • 可以用一张图来描述它们各自所处的位置:

  • 字符串常量池的结构

  • 在 Hotspot JVM 中,字符串常量池StringTable的本质是一张HashTable
  • 那么当我们说将一个字符串放入字符串常量池的时候,实际上放进去的是什么呢?
  • 以字面量的方式创建 String 对象为例,字符串常量池以及堆栈的结构如下图所示(忽略了 jvm 中的各种OopDesc实例):

  • 实际上字符串常量池 HashTable 采用的是数组加链表的结构,链表中的节点是一个个的HashTableEntry,而 HashTableEntry 中的 value 则存储了堆上 String 对象的引用
  • 那么,下一个问题来了,这个字符串对象的引用是什么时候被放到字符串常量池中的?
  • 具体可为两种情况:
    • 使用字面量声明 String 对象时,也就是被双引号包围的字符串,在堆上创建对象,并驻留到字符串常量池中(注意这个用词)
    • 调用intern()方法,当字符串常量池没有相等的字符串时,会保存该字符串的引用
  • 注意!在上面用到了一个词驻留,这里对它进行一下规范
  • 当说驻留一个字符串到字符串常量池时,指的是创建 HashTableEntry ,再使它的 value 指向堆上的 String 实例,并把 HashTableEntry放入字符串常量池,而不是直接把 String 对象放入字符串常量池中
  • 简单来说,可以理解为将 String 对象的引用保存在字符串常量池中
  • 把 intern() 方法放在后面细说,先主要看第一种情况,这里直接整理结论:
  • 在类加载阶段,JVM 会在堆中创建对应这些 class 文件常量池中的字符串对象实例,并在字符串常量池中驻留其引用
  • 这一过程具体是在 resolve 阶段(个人理解就是 resolution 解析阶段)执行,但是并不是立即就创建对象并驻留了引用,因为在 JVM 规范里指明了 resolve 阶段可以是 lazy 的
  • CONSTANT_String会在第一次引用该项的 ldc 指令被第一次执行到的时候才会 resolve
  • 就 HotSpot VM 的实现来说,加载类时字符串字面量会进入到运行时常量池,不会进入全局的字符串常量池,即在 StringTable 中并没有相应的引用,在堆中也没有对应的对象产生
  • 在弄清楚上面几个概念后,再回过头来,先看看用字面量声明 String 的方式,代码如下:

  • 反编译生成的字节码文件:

  • 解释一下上面的字节码指令:
    • 0: ldc,查找后面索引为#2 对应的项,#2 表示常量在常量池中的位置
    • 在这个过程中,会触发前面提到的lazy resolve,在 resolve 过程如果发现StringTable已经有了内容匹配的 String 引用,则直接返回这个引用,反之如果StringTable里没有内容匹配的 String 对象的引用,则会在堆里创建一个对应内容的 String 对象,然后在StringTable驻留这个对象引用,并返回这个引用,之后再压入操作数栈中
    • 2: astore_1,弹出栈顶元素,并将栈顶引用类型值保存到局部变量 1 中,也就是保存到变量s中
    • 3: return,执行void函数返回
  • 可以看到,在这种模式下,只有堆中创建了一个 "Hydra" 对象,在字符串常量池中驻留了它的引用
  • 并且,如果再给字符串 s2、s3 也用字面量的形式赋值为 "Hydra" ,它们用的都是堆中的唯一这一个对象
  • 再看一下以构造方法的形式创建字符串的方式:

  • 同样反编译这段代码的字节码文件:

  • 看一下和之前不同的字节码指令部分:
    • 0: new,在堆上创建一个 String 对象,并将它的引用压入操作数栈,注意这时的对象还只是一个空壳,并没有调用类的构造方法进行初始化
    • 3: dup,复制栈顶元素,也就是复制了上面的对象引用,并将复制后的对象引用压入栈顶;这里之所以要进行复制,是因为之后要执行的构造方法会从操作数栈弹出需要的参数和这个对象引用本身(这个引用起到的作用就是构造方法中的this指针),如果不进行复制,在弹出后会无法得到初始化后的对象引用
    • 4: ldc,在堆上创建字符串对象,驻留到字符串常量池,并将字符串的引用压入操作数栈
    • 6: invokespecial,执行 String 的构造方法,这一步执行完成后得到一个完整对象
  • 到这里可以看到一共创建了两个String 对象,并且两个都是在堆上创建的,且字面量方式创建的String 对象的引用被驻留到了字符串常量池中
  • 而栈里的s只是一个变量,并不是实际意义上的对象,不把它包括在内
  • 其实想要验证这个结论也很简单,可以使用 idea 中强大的 debug 功能来直观的对比一下对象数量的变化,先看字面量创建 String 方式:

  • 这个对象数量的计数器是在 debug 时,点击下方右侧Memory的Load classes弹出的
  • 对比语句执行前后可以看到,只创建了一个 String 对象,以及一个 char 数组对象,也就是 String 对象中的value
  • 再看看构造方法创建 String 的方式:

  • 可以看到,创建了两个 String 对象,一个 char 数组对象,也说明了两个 String 中的value指向了同一个char 数组对象,符合上面从字节码指令角度解释的结果
  • 最后再看一下下面的这种情况,当字符串常量池已经驻留过某个字符串引用,再使用构造方法创建String 时,创建了几个对象?

  • 答案是只创建一个对象,对于这种重复字面量的字符串,看一下反编译后的字节码指令:

  • 可以看到两次执行 ldc 指令时后面索引相同,而 ldc 判断是否需要创建新的 String 实例的依据是根据在第一次执行这条指令时, StringTable 是否已经保存了一个对应内容的 String 实例的引用
  • 所以在第一次执行 ldc 时会创建 String 实例,而在第二次 ldc 就会直接返回而不需要再创建实例了
  • 再看字面量和运行时常量池

  • JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化
  • 为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串常量池
  • 在JVM运行时区域的方法区中,有一块区域是运行时常量池,主要用来存储编译期生成的各种字面量和符号引用
  • 在java代码被 javac 编译之后,文件结构中是包含一部分 Constant pool 的
  • 比如以下代码:

  • 经过编译后,常量池内容如下:

  • 上面的Class文件中的常量池中,比较重要的几个内容:

  • 上面几个常量中,s 就是前面提到的符号引用,而 Hollis 就是前面提到的字面量
  • 而Class文件中的常量池部分的内容,会在运行期被运行时常量池加载进去
  • intern

  • 编译期生成的各种字面量和符号引用是运行时常量池中比较重要的一部分来源,但是并不是全部
  • 那么还有一种情况,可以在运行期向运行时常量池中增加常量
  • 那就是 String 的 intern 方法
  • 当一个 String 实例调用 intern() 方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用
  • intern()有两个作用,第一个是将字符串字面量放入常量池(如果池没有的话),第二个是返回这个常量的引用
  • 作为动词时它有禁闭、关押的意思,通过前面的介绍,与其说是将字符串关押到字符串常量池StringTable中,可能将它理解为缓存它的引用会更加贴切
  • String 的intern()是一个本地方法,可以强制将 String 驻留进入字符串常量池,可以分为两种情况:
    • 如果字符串常量池中已经驻留了一个等于此 String 对象内容的字符串引用,则返回此字符串在常量池中的引用
    • 否则,在常量池中创建一个引用指向这个 String 对象,然后返回常量池中的这个引用
  • 那下面看一下这段代码,它的运行结果应该是什么?

  • 输出打印:

  • 用一张图来描述它们的关系,就很容易明白了:

  • 在创建s1的时候,其实堆里已经创建了两个字符串对象StringObject1和StringObject2,并且在字符串常量池中驻留了StringObject2
  • 当执行s1.intern()方法时,字符串常量池中已经存在内容等于"Hydra"的字符串StringObject2,直接返回这个引用并赋值给s2
  • s1和s2指向的是两个不同的 String 对象,因此返回 false
  • s2指向的就是驻留在字符串常量池的StringObject2,因此s2=="Hydra"为 true,而s1指向的不是常量池中的对象引用所以返回 false
  • 上面是常量池中已存在内容相等的字符串驻留的情况,下面再看看常量池中不存在的情况,看下面的例子:

  • 执行结果:

  • 简单分析一下这个过程,第一步会在堆上创建 "Hy" 和 "dra" 的字符串对象,并驻留到字符串常量池中
  • 接下来完成字符串的拼接操作,前面说过,实际上 jvm 会把拼接优化成 StringBuilder 的 append 方法,并最终调用 toString 方法返回一个 String 对象
  • 在完成字符串的拼接后,字符串常量池中并没有驻留一个内容等于 "Hydra" 的字符串

  • 所以执行 s1.intern() 时,会在字符串常量池创建一个引用,指向前面 StringBuilder 创建的那个字符串,也就是变量 s1 所指向的字符串对象
  • 在《深入理解 Java 虚拟机》这本书中,作者对这进行了解释,因为从 jdk7 开始,字符串常量池就已经移到了堆中,那么这里就只需要在字符串常量池中记录一下首次出现的实例引用即可

  • 最后当执行 String s2 = "Hydra" 时,发现字符串常量池中已经驻留这个字符串,直接返回对象的引用,因此 s1 和 s2 指向的是相同的对象

  • 还是创建了几个对象

  • 解决了前面数 String 对象个数的问题,那么接着加点难度,看看下面这段代码,创建了几个对象

  • 先揭晓答案,只创建了一个对象!
  • 可以直观的对比一下源代码和反编译后的字节码文件:

  • 如果使用前面提到过的 debug 小技巧,也可以直观的看到语句执行完后,只增加了一个 String 对象,以及一个 char 数组对象
  • 并且这个字符串就是驻留在字符串常量池中的那一个,如果后面再使用字面量"abc"的方式声明一个字符串,指向的仍是这一个,堆中 String 对象的数量不会发生变化
  • 至于为什么源代码中字符串拼接的操作,在编译完成后会消失,直接呈现为一个拼接后的完整字符串,是因为在编译期间,应用了编译器优化中一种被称为常量折叠(Constant Folding)的技术
    • 常量折叠会将编译期常量的加减乘除的运算过程在编译过程中折叠
    • 编译器通过语法分析,会将常量表达式计算求值,并用求出的值来替换表达式,而不必等到运行期间再进行运算处理,从而在运行期间节省处理器资源
  • 而上边提到的编译期常量的特点就是它的值在编译期就可以确定,并且需要完整满足下面的要求,才可能是一个编译期常量:
    • 被声明为final
    • 基本类型或者字符串类型
    • 声明时就已经初始化
    • 使用常量表达式进行初始化
  • 下面通过几段代码加深对它的理解:

  • 执行结果:

  • 代码中字符串 h1 和 h2 都使用常量赋值,区别在于是否使用了 final 进行修饰,对比编译后的代码,s1 进行了折叠而 s2 没有
  • 可以印证上面的理论,final 修饰的字符串变量才有可能是编译期常量

  • 再看一段代码,执行下面的程序,结果会返回什么呢?

  • 答案是 false ,因为虽然这里字符串h2被final修饰,但是初始化时没有使用常量表达式,因此它也不是编译期常量
  • 那么到底什么才是常量表达式呢?
  • 在Oracle官网的文档中,列举了很多种情况,下面对常见的情况进行列举(除了下面这些之外官方文档上还列举了不少情况,如果有兴趣的话,可以自己查看):
    • 基本类型和 String 类型的字面量
    • 基本类型和 String 类型的强制类型转换
    • 使用+或-或!等一元运算符(不包括++和--)进行计算
    • 使用加减运算符+、-,乘除运算符*、 / 、% 进行计算
    • 使用移位运算符 >>、 <<、 >>>进行位移操作…
  • 至于从文章一开始就提到的字面量(literals),是用于表达源代码中一个固定值的表示法,在 Java中创建一个对象时需要使用new关键字,但是给一个基本类型变量赋值时不需要使用new关键字,这种方式就可以被称为字面量
  • Java 中字面量主要包括了以下类型的字面量:

  • 再说点题外话,和编译期常量相对的,另一种类型的常量是运行时常量,看一下下面这段代码:

  • 编译器能够在编译期就得到 s1 的值是 hello Hydra ,不需要等到程序的运行期间,因此 s1 属于编译期常量
  • 而对 s2 来说,虽然也被声明为 final 类型,并且在声明时就已经初始化,但使用的不是常量表达式,因此不属于编译期常量,这一类型的常量被称为运行时常量
  • 再看一下编译后的字节码文件中的常量池区域:

  • 可以看到常量池中只有一个 String 类型的常量 hello Hydra ,而 s2 对应的字符串常量则不在此区域
  • 对编译器来说,运行时常量在编译期间无法进行折叠,编译器只会对尝试修改它的操作进行报错处理
  • intern的正确用法

  • 在 String s3 = new String("tang").intern(); 中,其实 intern 是多余的?
  • 因为就算不用 intern ,Hollis作为一个字面量也会被加载到Class文件的常量池,进而加入到运行时常量池中,为啥还要多此一举呢?
  • 到底什么场景下才需要使用 intern 呢?
  • 在解释这个之前,先来看下以下代码:

  • 在经过反编译后,得到代码如下:

  • 可以发现,同样是字符串拼接,s3和s4在经过编译器编译后的实现方式并不一样
  • s3被转化成 StringBuilder 及 append ,而s4被直接拼接成新的字符串
  • 还能发现, String s3 = s1 + s2; 经过编译之后,常量池中是有两个字符串常量的分别是 Hollis 、 Chuang(其实 Hollis 和 Chuang 是 String s1 = "Hollis"; 和 String s2 = "Chuang"; 定义出来的),拼接结果 HollisChuang 并不在常量池中
  • 如果代码只有 String s4 = "Hollis" + "Chuang"; ,那么常量池中将只有 HollisChuang 而没有"Hollis" 和 "Chuang"
  • 究其原因,是因为常量池要保存的是已确定的字面量值
  • 也就是说,对于字符串的拼接,纯字面量和字面量的拼接,会把拼接结果作为常量保存到字符串池
  • 如果在字符串拼接中,有一个参数是非字面量,而是一个变量的话,整个拼接操作会被编译成 StringBuilder.append ,这种情况编译器是无法知道其确定值的
  • 只有在运行期才能确定
  • 那么有了这个特性了, intern 就有用武之地了
  • 那就是很多时候,在程序中得到的字符串是只有在运行期才能确定的,在编译期是无法确定的,那么也就没办法在编译期被加入到常量池中
  • 这时候,对于那种可能经常使用的字符串,使用 intern 进行定义,每次JVM运行到这段代码的时候,就会直接把常量池中该字面值的引用返回,这样就可以减少大量字符串对象的创建了
  • 举一个例子:

  • 在以上代码中,明确的知道,会有很多重复的相同的字符串产生,但是这些字符串的值都是只有在运行期才能确定的
  • 所以,只能通过 intern 显示的将其加入常量池,这样可以减少很多字符串的重复创建

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

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

相关文章

KubeEdge官方示例运行成功_Counter Demo 计数器

运行KubeEdge官方示例_Counter Demo 计数器 KubeEdge Counter Demo 计数器是一个伪设备&#xff0c;用户无需任何额外的物理设备即可运行此演示。计数器在边缘侧运行&#xff0c;用户可以从云侧在 Web 中对其进行控制&#xff0c;也可以从云侧在 Web 中获得计数器值,原理图如下…

前端web入门-移动web-day10

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 移动Web基础 手机模拟器 屏幕分辨率 视口 二倍图 适配方案 rem 适配方案 rem 媒体查询 rem – …

使用java生成mvt切片的方法

如何使用java生成geoserver的矢量切片供前端&#xff08;mapbox等&#xff09;调用 目录新的想法Java能为切片做什么如何生成切片如何转换xyz数据如何查询如何输出mvt格式给前端前端如何调用 目录 好久没发博客了&#xff0c;每日或忙碌、或悠闲、或喜或悲、时怅时朗&#xff…

访问学者怎样准备申请推荐信

作为访问学者&#xff0c;申请推荐信是非常重要的一步&#xff0c;它能够在您的申请过程中增加信誉度和竞争力。一个优秀的推荐信可以更好地展现您的学术能力、研究潜力和个人品质。以下是知识人网小编整理的关于如何准备申请推荐信的建议&#xff1a; 1. 确定推荐人&#xff1…

阿里云OSS上传文件工具类

个人主页&#xff1a;金鳞踏雨 个人简介&#xff1a;大家好&#xff0c;我是金鳞&#xff0c;一个初出茅庐的Java小白 目前状况&#xff1a;22届普通本科毕业生&#xff0c;几经波折了&#xff0c;现在任职于一家国内大型知名日化公司&#xff0c;从事Java开发工作 我的博客&am…

20本期刊影响因子上涨,7月SCI/SSCI/AHCI/EI刊源表已更新!

2023年7月SCI/SSCI/AHCI/EI期刊目录更新 2023年6月28日发布的最新《期刊引证报告》中&#xff0c;我处合作期刊中&#xff0c;7月刊源表有20本期刊影响因子上涨&#xff0c;同时新增多本快刊&#xff01; 重磅&#xff01;2023年JCR正式发布&#xff08;附影响因子名单下载&a…

[github-100天机器学习]day2 simple linear regression

https://github.com/LiuChuang0059/100days-ML-code/blob/master/Day2_SImple_Linear_regression/README.md 简单线性回归 使用单一特征预测响应值。基于自变量X来预测因变量Y的方法&#xff0c;假设两者线性相关&#xff0c;寻找一种根据特征或自变量X的线性函数来预测Y。 目…

工资难以突破升职加薪必看,资深测试经理教你怎么做好“管理岗”!

要了解测试管理岗位需要具备的素质&#xff0c;我们先来看下测试管理岗位的职责。以下是 Boss 直聘上某几家的公司的测试经理的岗位要求&#xff1a; 如果你想学习接口自动化测试&#xff0c;我这边给你推荐一套视频&#xff0c;这个视频可以说是B站播放全网第一的接口自动化测…

从零开始搭建STM32CubeMX开发环境

本文记录一下如何从零开始使用STM32CubeMX&#xff0c;包括软件的安装&#xff0c;环境的搭建&#xff0c;配置代码的生成等&#xff1b; 本文以STM32G030C8T6为例&#xff0c;如果你的单片机不是以STM32G030C8T6为例&#xff0c;换成你的单片机类型即可&#xff0c;过程都是通…

03_单一职责模式

单一职责 在软件组件的设计中&#xff0c;如果责任划分的不清晰&#xff0c;使用继承得到的结果往往是随着需求的变化&#xff0c;子类急剧膨胀&#xff0c;同时充斥着重复代码&#xff0c;这时候的关键是划清责任。 装饰模式 动态&#xff08;组合&#xff09;地给一个对象增…

系统没有“internet信息服务(IIS)管理器”

系统没有“internet信息服务&#xff08;IIS&#xff09;管理器” 解决方案1.打开控制面板&#xff0c;找到并打开程序。2.找到并打开程序里的启用或关闭windows功能。3.在‘Internet Information Services’下的‘web管理工具’中找到IIS相关功能&#xff0c;在前面的复选框中…

探索数字孪生世界:市场上五款炙手可热的数字孪生产品介绍

山海鲸可视化&#xff1a;山海鲸可视化是一款国内领先的数字孪生软件&#xff0c;具有强大的GIS功能和可视化效果&#xff0c;广泛应用于城市规划、建筑设计和智慧城市等领域。 华为云数字孪生&#xff1a;华为云数字孪生平台提供了全面的数字化解决方案&#xff0c;包括智慧城…

链表中倒数第k个结点(快慢指针问题)

⭐️ 往期相关文章 &#x1f4ab;链接1&#xff1a;leetcode 876.链表的中间结点(快慢指针问题) &#x1f4ab;链接2&#xff1a;leetcode 206.反转链表 &#x1f4ab;链接3&#xff1a;leetcode 203.移除链表元素 &#x1f4ab;链接4&#xff1a;数据结构-手撕单链表代码详解…

实训笔记7.4

实训笔记7.4 7.4一、座右铭二、IDEA集成开发环境的安装和使用三、DEBUG断点调试四、Java设计模式4.1 适配器模式4.2 动态代理模式4.3 单例设计模式 五、Java中网络编程5.1 网络编程三个核心要素5.2 TCP网络编程 六、基于网络编程的聊天系统6.1 需求分析6.2 系统设计6.2.1 概要设…

解放运营人员:钡铼技术S475物联网网关实现养殖环境的远程监控与告警

在养殖行业中&#xff0c;对环境参数的精确监测与控制至关重要。然而&#xff0c;传统的监测方法往往存在诸多痛点&#xff0c;如数据采集不准确、传输速度慢、可视化效果差等。为了解决这些问题&#xff0c;钡铼技术公司推出了其旗舰产品——S475多功能RTU&#xff0c;该产品在…

如何利用思维导图提高项目管理效率

思维导图 是一种强大的工具&#xff0c;可以帮助我们更好地组织和管理项目。它是一种以图形方式展现思维和概念之间关系的方法&#xff0c;通过将主题、子主题和分支串联起来&#xff0c;帮助我们清晰地了解任务的层次结构和相互关系。在项目管理中&#xff0c;思维导图可以帮助…

数据生成实体类解决方案

文章目录 数据生成实体类解决方案 简介工作原理解析JSON生成实体类示例JSON消息解析JSON核心方法&#xff1a;调用示例&#xff1a;将数据保存到实体类中。将实体类转为输出为JSON。 思考 数据生成实体类解决方案 直接将xml导入到Studio里即可。下载文件连接&#xff1a; CSDN…

GPIO点灯

简述&#xff1a;本人使用教材为《嵌入式系统原理与应用》&#xff0c;GPIOCON控制输出&#xff0c;GPIODAT控制高电平和低电平&#xff0c;高电平点亮&#xff0c;低电平熄灭。

【若依】框架搭建,前端向后端如何发送请求,验证码的实现

若依框架 若依框架&#xff08;Ruoyi&#xff09;是一款基于Spring Boot和Spring Cloud的开源快速开发平台。它提供了一系列的基础功能和通用组件&#xff0c;能够帮助开发者快速构建企业级应用。若依框架采用了模块化的设计理念&#xff0c;用户可以选择需要的功能模块进行集…

全网最全,华为可信专业级认证介绍

1&#xff1a;华为可信专业级认证是什么&#xff1f; 华为在推动技术人员的可信认证&#xff0c;算是一项安全合规的工作。专业级有哪些考试呢&#xff1f;共有四门&#xff1a; 科目一&#xff1a;上级编程&#xff0c;对比力扣2道中等、1道困难&#xff1b; 科目二&#xff…