Java中的强引用、软引用、弱引用、虚引用与引用队列 通俗举例实战详解

文章目录

  • 1. 基本概念
  • 2. 代码演示
    • 2.1 软引用代码演示
    • 2.2 弱引用代码演示
    • 2.3 弱引用+引用队列代码演示
    • 2.4 虚引用代码演示
    • 2.5 虚引用+引用队列代码演示
  • 3. 实战样例
    • 3.1 利用软引用实现资源对象缓存
    • 3.2 利用弱引用实现临时行为数据缓存
    • 3.3 利用虚引用+引用队列实现资源释放

本次实验Java版本:JDK 1.8.0_152_release

1. 基本概念

本节先了解一下概念,看不懂没关系,后续会详解。

Java中的引用可以按强弱程度分为四种,JVM对不同程度的引用回收策略不同:

强引用(Strong Reference):我们平时用的都是强引用。例如:MyObject myObj = new MyObject();

  • 回收:只要有引用,就不会被回收。

软引用(Soft Reference):使用SoftReference显式声明。

  • 回收:当JVM内存不够时,会对软引用对象进行回收。
  • 应用场景:做资源类缓存。
  • 使用样例:
     MyObject myObject = new MyObject("Amy");  // 从数据库中获取数据SoftReference<MyObject> reference = new SoftReference<>(myObject);  // 增添软引用// do something ...myObject = reference.get(); // 尝试获取myObject对象if (myObject == null) {// 没获取到,说明已经被JVM回收了myObject = new MyObject("Amy");  // 重新从数据库中获取数据} else {// 没有被JVM回收}
    

弱引用(Weak Reference):使用WeakReference显式声明。

  • 回收:当JVM下次执行垃圾回收时,就会立刻回收。
  • 应用场景:做临时行为类数据缓存。
  • 使用样例:和上面SoftReference一样,把SoftReference改成WeakReference即可。

虚引用(Phantom Reference):也称为“幽灵引用”、“幻影引用”等。单纯的将其标记一下,配合引用队列(ReferenceQueue)进行回收前的一些操作

  • 回收:当JVM执行垃圾回收时,就会立刻回收
  • 应用场景:资源释放(用来代替finalize方法)
  • 特殊点:虚引用的reference.get()方法一定会返回null(源码就是直接return null,这也是为什么叫虚引用的原因。
  • 使用样例:建后续引用队列。

引用队列:在定义软/弱/虚引用时,可以传个引用队列(虚引用必须传),这样对象在被回收之前会进入引用队列,可以显式的对其进行一些操作。

  • 作用:可以在该对象被回收时主动收到通知,来对其进行一些操作。
  • 应用场景:资源释放

2. 代码演示

本节是对软/弱/虚引用和引用队列的作用机制代码演示。

2.1 软引用代码演示

import java.lang.ref.Reference;
import java.lang.ref.SoftReference;public class SoftReferenceTest {public static void main(String[] args) {// 这里定义了obj对象,为正常的强引用String obj = new String("myObj");// 为该对象增加软引用// 此时它同时拥有两种引用,即obj同时拥有强引用和软引用Reference<String> softReference = new SoftReference<>(obj);// 解除obj的强引用,此时obj只剩下了软引用obj = null;// 调用GC进行垃圾回收。(只是通知,并不一定真的做垃圾回收,这里假设做了)System.gc();// 尝试从软引用中获取obj对象// 若没有获取到,说明该对象已经被JVM释放// 若获取到了,说明还没有被释放String tryObj = softReference.get();System.out.println("try obj:" + tryObj);}}

输出结果:

try obj:myObj

解释:

上述样例中,我们为obj对象绑定了软引用,在解除了强引用后尝试进行GC。可以看到,GC并没有回收obj对象。这是因为软引用的回收规则为:当JVM内存不够时,才会进行回收,上面的简单例子中,JVM内存显然不会不够用,因此我们可以通过reference对象拿到obj对象。

2.2 弱引用代码演示

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;public class WeakReferenceTest {public static void main(String[] args) {// 这里定义了obj和obj2对象,为正常的强引用String obj1 = new String("myObj1");String obj2 = new String("myObj2");// 为它们增加弱引用// 此时它们同时拥有两种引用,即obj同时拥有强引用和弱引用Reference<String> reference1 = new WeakReference<>(obj1);Reference<String> reference2 = new WeakReference<>(obj2);// 解除obj1的强引用,然后执行GCobj1 = null;System.gc();// 解除obj2的强引用,不执行GCobj2 = null;/*** 尝试从若引用中获取obj1对象* 若没有获取到,说明该对象已经被JVM释放* 若获取到了,说明还没有被释放*/String tryObj1 = reference1.get();// 这里tryObj1将会返回null,因为obj解除强引用后执行了GC操作// 因此obj1被释放了,所以获取不到System.out.println("try obj1:" + tryObj1);String tryObj2 = reference2.get();// 这里obj2不是null,因为obj2解除了强引用后并没有执行GC,// 因此obj2并没有被释放,所以可以获取到System.out.println("try obj2:" + tryObj2);}}

输出结果:

try obj1:null
try obj2:myObj2

解释:弱引用的释放规则为“下次执行GC时,会将对象进行释放”。在上述代码中,obj1执行了GC,而obj2没有执行GC,因此obj1null,而obj2不为null

2.3 弱引用+引用队列代码演示

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;public class WeakReference2Test {public static void main(String[] args) throws InterruptedException {// 定义引用队列ReferenceQueue<String> referenceQueue = new ReferenceQueue<>();// 这里定义了obj为正常的强引用String obj1 = new String("myObj1");// 为它增加弱引用// 此时它同时拥有两种引用,即obj同时拥有强引用和弱引用// 在为obj对象绑定弱引用时,同时传入了引用队列。// 这样“obj对象”在被回收之前,其对应的“引用对象”就会进入引用队列Reference<String> reference1 = new WeakReference<>(obj1, referenceQueue);  // 这里传入引用队列System.out.println("reference1: " + reference1);// 解除obj1强引用,然后执行GCobj1 = null;// 尝试从引用队列中获取引用对象。Reference<String> pollRef1 = (Reference<String>) referenceQueue.poll();// 这里会返回null,因为obj1虽然没有了强引用,但是还没有被标记为“可回收”// 因此,“obj1”的引用对象并没有进入到引用队列中System.out.println("pollRef1: " + pollRef1);// 执行GC操作System.gc();// 给些时间让reference对象进入引用队列Thread.sleep(100);// 再次尝试从引用队列中获取“引用对象”Reference<String> pollRef2 = (Reference<String>) referenceQueue.poll();// 这次就不为null了,因为`obj1`已经被标记为“可回收”,// 因此其对应的“引用对象”就会进入引用队列System.out.println("pollRef2: " + pollRef2);// 尝试从引用对象中获取`obj`对象// 这里两种可能:①null;② `myObj1`// 因为当`obj1`被标记为“可回收”时,其引用对象就会进入引用队列,但此时obj1是否被回收并不知道// ① 若obj1已经被回收了,这里就会返回null。(也是最常见的)// ② 若Obj1暂时还没被回收,这里就会返回“myObj1”(这个很难复现)System.out.println("pollRef2 obj: " + pollRef2.get());}}

输出

reference1: java.lang.ref.WeakReference@49c2faae
pollRef1: null
pollRef2: java.lang.ref.WeakReference@49c2faae
pollRef2 obj: null

上述代码中一共进行了两次从引用队列中获取“引用对象”。第一次,由于还没有执行GC操作,obj1没有被标记为“可回收”状态,所以其对应的引用对象reference1也就没有进入引用队列。第二次,由于执行了GC操作,obj1被标记为了“可回收”,因此可以拿到reference1对象,但由于obj1已经被回收了,因此使用reference1.get()却拿不到obj1对象了。

这里再额外说明几点大家可能疑惑的点:

  1. 将“①对象标记为是否可回收”和“②释放对象”两个动作基本上是同时发生的,执行完动作①就会执行动作②。所以一般我们都只能从引用队列中拿到“引用对象”,但是再用引用对象去拿对象就拿不到了,因为已经被释放了。
  2. 只要对象被标记为“可释放”,那么该对象的“引用对象”就会进入引用队列,后续该对象随时可能会被释放。因此有可能会出现以下情况:
    Reference<String> pollRef1 = (Reference<String>) referenceQueue.poll();
    // 不为null,因为这个时候还没被释放
    System.out.println("pollRef1: " + pollRef1.get()); 
    // 为null,被释放了
    System.out.println("pollRef1: " + pollRef1.get());
    

2.4 虚引用代码演示

虚引用必须要配合引用队列,要不然没有任何意义:

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;public class PhantomReferenceTest {public static void main(String[] args) {ReferenceQueue<String> queue = new ReferenceQueue<>();// 这里定义了obj对象,为正常的强引用String obj = new String("myObj");// 为该对象增加虚引用// 此时它同时拥有两种引用,即obj同时拥有强引用和虚引用// 虚引用构造方法要求必须要传引用队列Reference<String> phantomReference = new PhantomReference<>(obj, queue);// obj的强引用还在,因此其一定不会被释放// 尝试使用虚引用获取obj对象String tryObj = phantomReference.get();// tryObj为null,因为phantomReference.get()的实现就是`return null;`System.out.println("try obj:" + tryObj);}}

输出:

try obj:null

上面的代码中,虽然obj没有被释放,但用虚引用依然无法获取obj对象。这也是为什么人们说“虚引用是虚幻的,必须要配合引用队列一起用,要不然就没意义了”

2.5 虚引用+引用队列代码演示

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;public class PhantomReferenceTest2 {public static void main(String[] args) {ReferenceQueue<String> queue = new ReferenceQueue<>();// 这里定义了obj对象,为正常的强引用String obj = new String("myObj");// 为该对象增加虚引用// 此时它同时拥有两种引用,即obj同时拥有强引用和虚引用// 虚引用构造方法要求必须要传引用队列Reference<String> phantomReference = new PhantomReference<>(obj, queue);System.out.println("phantomReference:" + phantomReference);// 解除obj的强引用obj = null;System.gc();// 从引用队列中获取引用对象。// 由于obj已经是“可释放或已释放”状态,因此可以获取到`phantomReference`System.out.println("referenceQueue:" + queue.poll());}}

3. 实战样例

3.1 利用软引用实现资源对象缓存

场景:假设我们有一个资源类Resource,它占用100M内存。加载过程很慢,我们既不想因为导致OOM,又想让它缓存在JVM里,我们就可以用软引用实现。

import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;public class SoftReferenceAppTest {static class Resource {private byte[] data = new byte[1024 * 1024 * 100]; // 该资源类占用100M内存private static int num = 0;private static SoftReference<Resource> resourceHolder = null;public static Resource getInstance() {if (resourceHolder != null) {// 从缓存中获取Resource resource = resourceHolder.get();if (resource != null) {return resource;}}// 缓存中没有,重新new一个System.out.println("从数据库中获取资源类:" + num);num ++;Resource resource = new Resource();resourceHolder = new SoftReference<>(resource);return resource;}public String getData() {return "data";}}public static void main(String[] args) {// 使用资源类System.out.println(Resource.getInstance().getData());// 执行各种各样的事情,最终jvm内存满了,然后回收了resource。int i = 0;List<byte[]> list = new ArrayList<>();while(true) {list.add(new byte[1024*1024*50]);i++;// 使用资源类Resource.getInstance().getData();if (i > 10000) {break;}}}}

输出:

从数据库中获取资源类:0
data
从数据库中获取资源类:1
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat jvm.SoftReferenceAppTest$Resource.<init>(SoftReferenceAppTest.java:11)at jvm.SoftReferenceAppTest$Resource.getInstance(SoftReferenceAppTest.java:30)at jvm.SoftReferenceAppTest.main(SoftReferenceAppTest.java:52)

上述例子中,我们的Resource类使用了软引用SoftReference来进行缓存。

之后在模拟中,执行过程如下:

  1. 首先获取了资源类对象,并将这个对象绑定了软引用,但并不存在强引用
  2. 使用资源类,正常从软引用中获取缓存的资源类对象
  3. 不断的往JVM中添加数据list.add(new byte[1024*1024*50]);,最终导致内存不够用
  4. 由于内存不够用,因此GC回收时回收了资源类对象,因此重新生成了资源类对象
  5. 最后,JVM内存不够了,最终OOM

3.2 利用弱引用实现临时行为数据缓存

抽象场景:在某些场景中,用户的操作会产生一些后台数据,而这些数据用户可能会在短时间内再次使用,但也可能不使用。这种时候就可以使用弱引用WeakReference进行缓存。

样例场景:后台提供了一个word转PDF的功能,但由于某些用户可能会连点,或由于网络不好导致短时间内再次对同一文档进行转换。而转换过程又比较耗资源,因此使用WeakReference进行缓存。

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;public class WeakReferenceAppTest {// 缓存对象static Map<String, WeakReference<String>> cacheMap = new HashMap<>();// 将word数据转为pdf数据,不使用缓存public static String wordToPDF(String wordData) {return "pdf " + wordData;}// 将word数据转为pdf数据,使用缓存public static String wordToPDFWithCache(String wordData) {// 先看缓存里有没有if (cacheMap.keySet().contains(wordData)) {String pdfData = cacheMap.get(wordData).get();if (pdfData != null) {System.out.println("使用缓存数据");return pdfData;}}String pdfData = "pdf " + wordData;System.out.println("无缓存,执行转换!");cacheMap.put(wordData, new WeakReference<>(pdfData));return pdfData;}public static void main(String[] args) throws InterruptedException {// 程序A,不使用WeakReference做缓存{System.out.println("---程序A(不用缓存)----");// 用户A将word1转为了pdfSystem.out.println(wordToPDF("word1"));// 用户A因为手快连点了两次,由于没有进行缓存,因此又执行了一遍wordToPDFSystem.out.println(wordToPDF("word1"));}System.out.println();// 程序B,使用WeakReference做缓存{System.out.println("---程序B(使用缓存)----");// 用户A将word1转为了pdfSystem.out.println(wordToPDFWithCache("word1"));// 用户A因为手快连点了两次,由于有缓存,直接返回System.out.println(wordToPDFWithCache("word1"));// 过了若干时间System.gc();Thread.sleep(1000);// 用户A再次对word1进行转pdfSystem.out.println(wordToPDFWithCache("word1"));}}}

输出:

---程序A(不用缓存)----
pdf word1
pdf word1---程序B(使用缓存)----
无缓存,执行转换!
pdf word1
使用缓存数据
pdf word1
无缓存,执行转换!
pdf word1

3.3 利用虚引用+引用队列实现资源释放

应用场景:替代finalize,因为其有很多缺点:

finalize的缺点:

(1)无法保证什么时间执行。
(2)无法保证执行该方法的线程优先级。
(3)无法保证一定会执行。
(4)如果在终结方法中抛出了异常,并且该异常未捕获处理,则当前对象的终结过程会终止,且该对象处于破坏状态。
(5)影响GC的效率,特别是在finalize方法中执行耗时较长的逻辑。
(6)有安全问题,可以进行终结方法攻击。

最优解决方案:使用try-with-resource。

其次解决方案:使用虚引用+引用队列。

最好两种同时用。

样例场景:我们现在有一个比较耗资源的Resource类(也可以是IO等),我们没有办法保证try-with-resourcefinalize能正确释放。因此我们还要启一个后台线程来监控目前是否有未释放的资源。如果有,则释放资源。若释放失败,则发送通知消息。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;public class PhantomReferenceAppTest {// 引用队列,专门负责对Resource对象的释放static ReferenceQueue<Resource> referenceQueue = new ReferenceQueue<>();static Map<PhantomReference, String /*资源ID*/> referenceIdMap = new HashMap<>();static class Resource {public static Resource getInstance(String resourceID) {Resource resource = new Resource();// 将resource与一个虚引用绑定,并传入公共引用队列// 这样当resource资源不再使用时,就可以释放资源。PhantomReference phantomReference = new PhantomReference<>(resource, referenceQueue);referenceIdMap.put(phantomReference, resourceID); // 记录这个引用对象对应的资源ID,用于后续释放资源return resource;}// 注意:这个必须是静态方法。因为PhantomReference根本拿不到Resource的实例。// 假设使用软/弱引用,也不一定能拿到Resource,因为Resource对象很有可能已经被JVM释放了public static void realise(String resourceID) {System.out.println("释放资源:" + resourceID);}}public static void main(String[] args) throws InterruptedException {// 定义一个专门用于资源释放的线程new Thread(new Runnable() {@SneakyThrows@Overridepublic void run() {while (true) {Thread.sleep(100);// 尝试从引用队列中获取引用对象PhantomReference phantomReference = (PhantomReference) referenceQueue.poll();if (phantomReference == null) {continue;}String resourceId = referenceIdMap.get(phantomReference); // 获取resourceIDResource.realise(resourceId);referenceIdMap.remove(phantomReference);}}}).start();Resource resource1 = Resource.getInstance("res1");Resource resource2 = Resource.getInstance("res2");Resource resource3 = Resource.getInstance("res3");resource3 = null; // resource3使用完毕,执行了GCSystem.gc();Thread.sleep(1000);resource1 = null; // resource1使用完毕,没有执行GCresource2 = null; // resource2使用完毕,执行GCSystem.gc();}
}

输出:

释放资源:res3
释放资源:res2
释放资源:res1

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

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

相关文章

ArcGIS Pro SDK根据Xml/Json文件反向生成几何

需求&#xff1a; geometry文件导出后的xml&#xff0c;在另一台电脑上反向生成geometry 解决方案&#xff1a; 点 MapPoint minPointImport MapPointBuilderEx.FromXml(xml); 线 包络线 Envelope envelopeImport EnvelopeBuilderEx.FromXml(xml); 面 var geometryB…

认识产品经理以及Axure简单安装与入门

目录 一.认识产品经理 1.1.项目团队 1.2.概述 1.3.认识产品经理 1.4.产品经理工作范围 1.5.产品经理工作流程 1.6.产品经理的职责 1.7.产品经理的分类 1.8.产品经理能力要求 1.9.产品工具 1.10.产品体验报告 二.Axure简介 三.应用场景 四.安装与汉化 4.1.安装 4…

如果可以,我也想把“贵阳地铁3号线开通纪念套卡”带回家!

点击视频&#xff0c;解锁“贵阳地铁3号线开通纪念套卡”&#xff01; 在贵阳地铁3号线开通初期运营之际&#xff0c;贵阳市信捷科技有限公司精心设计了“贵阳地铁3号线开通纪念套卡”&#xff0c;定于12月16日正式对外发售&#xff0c;每套售价人民币88元&#xff0c;每套2枚&…

Vue2面试题:说一下路由模式hash和history的区别?

在单页面应用SPA中&#xff0c;路由描述的是URL与视图之间的映射关系&#xff0c;这种映射是单向的&#xff0c;即URL变化引起视图更新&#xff08;无需刷新页面&#xff09;。 1、hash模式 原理&#xff1a; 用 url #后面的hash值 来模拟一个完整的url&#xff0c;直接刷新…

指纹浏览器有什么用?AdsPower 指纹浏览器都有哪些优势?

说到指纹浏览器&#xff0c;各位跨境卖家肯定都不陌生&#xff0c;指纹浏览器已经成为跨境电商不可或缺的有力工具&#xff0c;那么它具体有什么作用呢&#xff1f;如今市场上指纹浏览器品牌琳琅满目&#xff0c;东哥有没有什么推荐呢&#xff1f;在这里&#xff0c;东哥将为大…

matter模组有无源测试事例

测试一款matter模组的硬件性能 1.1 天线阻抗、电压驻波比测试 主要测试&#xff1a;PCB板载天线设计效率及板材PCB铜面的平整度等 1.2 模组有源数据测试 主要测试&#xff1a;模组的阻抗匹配、频偏等情况 1.3 模组传输能量精度 主要测试&#xff1a;矢量误差等数据 1.4 模…

Unity2023.3(Unity6)版本开始将可以发布WebGPU

翻译一段官网上的话&#xff1a; 利用Unity 2023.3(正式发布时应该称为Unity6)中最新的WebGPU图形API集成&#xff0c;尝试最大限度的提升您的网络游戏的真实感。 通过与谷歌的战略合作&#xff0c;Unity实时3D平台的强大的图形功能现在为图形丰富的网络游戏进行微调&#xff0…

次模、K次模和超模有什么区别与联系,主要的作用是什么?

“次模”&#xff08;Submodularity&#xff09;、“K次模”&#xff08;K-submodularity&#xff09;和"超模"&#xff08;Supermodularity&#xff09;是描述集合函数性质的概念。以下是它们的区别、联系以及主要作用&#xff1a; 次模&#xff08;Submodularity&a…

提升英语学习效率,尽在Eudic欧路词典 for Mac

Eudic欧路词典 for Mac是一款专为英语学习者打造的强大工具。无论您是初学者还是高级学习者&#xff0c;这款词典都能满足您的需求。 首先&#xff0c;Eudic欧路词典 for Mac具备丰富的词库&#xff0c;涵盖了各个领域的单词和释义。您可以轻松查询并学习单词的意思、用法和例…

猫粮哪个牌子好?盘点十大主食冻干猫粮品牌排行榜!

近年来&#xff0c;冻干猫粮作为备受追捧的高品质猫粮&#xff0c;吸引了越来越多养猫人的关注。新手养猫就弄不明白了&#xff0c;什么是冻干猫粮呢&#xff1f;冻干猫粮可以作为日常主食一直喂吗&#xff1f; 作为一位6年养猫人&#xff0c;我会用最简单的文字告诉你主食冻干…

安装NLTK Data

文章目录 NLTK离线安装1. 获取安装包2. 放置nltk_data文件3. Demo4. 参考链接 关注公众号&#xff1a;『AI学习星球』 算法学习、4对1辅导、论文辅导或核心期刊可以通过公众号或CSDN滴滴我 nltk库是python语言为自然语言处理提供的一个功能强大&#xff0c;简单易用的函数库&a…

android 13.0 当卸载otg设备开机不加载otg设备功能实现

1.概述 在13.0定制化rom产品开发过程中,客户有功能需求,通过系统属性值控制是否加载挂载otg设备,当设置为卸载模式时, 要求不能挂载otg设备,开机也不能挂载otg设备,接下来分析相关功能实现 2.卸载otg设备开机不加载otg设备的核心代码 frameworks/base/services/core/ja…

Todesk、向日葵等访问“无显示器”主机黑屏问题解决

我的环境是 ubuntu 22.04 安装 要安装 video dummy&#xff0c;请在终端中运行以下命令&#xff1a; sudo apt install xserver-xorg-video-dummy配置 video dummy 的配置文件请自行搜索 使用任何文本编辑器打开此文件。 我的是 /etc/X11/xorg.conf 默认配置文件包含以下内…

StrComp( ) 函数及instr( )函数示例(字符串比较与查找)

在编程中经常会遇到字符串比较与查找&#xff0c;此时就需要用到函数来解决了。如下&#xff1a; 这两个函数都有个共同点&#xff0c;如果严格比较字符&#xff08;区分大小写&#xff09;&#xff0c;最后一位没有1&#xff0c;如果不区分大小写&#xff0c;最后一位有1&…

Java Web 01_HTML4HTML5基础标签语法

HMTL基础 1.什么是HTML Hyper Text Markup Language (超文本标记语言)标记又俗称标签(tag)&#xff0c;一般格式&#xff1a; <tagName></tagName> 如 <h1></h1>标签里还可以有属性(Attribute)&#xff1a; <tagName Atrribute “value” />…

C++ STL vector容器详解

vector 容器是 STL 中最常用的容器之一&#xff0c;它和 array 容器非常类似&#xff0c;都可以看做是对 C 普通数组的“升级版”。不同之处在于&#xff0c;array 实现的是静态数组&#xff08;容量固定的数组&#xff09;&#xff0c;而 vector 实现的是一个动态数组&#xf…

Debezium日常分享系列之:Debezium 2.5.0.CR1发布

Debezium日常分享系列之&#xff1a;Debezium 2.5.0.CR1发布 一、重大变化1.Cloud Event 标头的架构名称2.MySQL BIT 默认长度 二、新功能和改进1.重新选择列2.Debezium Server - 用于 Apache Kafka 接收器的 StreamNameMapper3.增量快照水印的 INSERT/DELETE 语义4.Debezium 服…

1.7 实战:Postman请求Post接口-登录

上一小节我们实战了使用Postman请求Get接口。本小节我们来使用Postman请求Post接口。 我们来测试一下登录,之前已经创建好了Collections。我们选择登录页下的登录这个请求。地址也是跟之前一样,我们打开校园二手交易系统,打开浏览器开发者工具,输入用户名和密码,点击登录…

力扣22. 括号生成(java 回溯法)

Problem: 22. 括号生成 文章目录 题目描述思路解题方法复杂度Code 题目描述 思路 我们首先要知道&#xff0c;若想生成正确的括号我们需要让右括号去适配左括号&#xff0c;在此基础上我们利用回溯去解决此题目 1.题目给定n个括号&#xff0c;即当回溯决策路径长度等于 2 n 2n…

网络基础2

三层交换机&#xff1a;路由器交换机 创建vlan 配置0/0/2串口为vlan2&#xff0c;3接口为vlan3 三层交换机的串口是不能直接配置地址&#xff0c;要在虚拟接口&#xff08;vlan的接口&#xff09;配置IP地址 配置vlan1的虚拟接口 此时vlan1的主机能ping通三层交换机串口1的地址…