kotlin的密封类

引言

密封类是一种特殊的类,它用来表示受限的类继承结构,即一个类只能有有限的几种子类,而不能有任何其他类型的子类。

这不就是JAVA的枚举么。

概念

密封类使用sealed关键字声明,

在Kotlin 1.0中,密封类的所有子类必须嵌套在密封类内部;

在Kotlin 1.1中,这个限制放宽了,允许将子类定义在同一个文件中;

在Kotlin 1.5中,这个限制进一步放宽了,允许将子类定义在任何地方,只要保证子类可见性不高于父类。

密封类通常用于代替枚举类。密封类的优点在于可以更灵活地定义子类,而枚举类的每个成员都是固定的。密封类还可以帮助你编写更加类型安全的代码

密封类最大的优点是可以配合when表达式实现完备性检查(exhaustive check),即编译器可以检测出是否覆盖了所有可能的分支情况,如果没有则会报错或提示警告。这样可以避免遗漏某些情况导致逻辑错误或运行时异常。

。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

很抽象。

密封类和枚举的区别是什么?

相同点:所有成员都属于本类本身

不同点:枚举只能有一个实例,而密封类的子类可以有多个实例。

密封类的子类可以携带自己独有的状态参数以及行为方法来记录更多的实现信息以完成更多的功能,这是枚举类所不具备的。

例子:

sealed class MyScore {object FAIL_A_GRADE : MyScore()//分数差object PASS_THE_MARK : MyScore()//分数及格object SCORE_WELL : MyScore()//分数良好class EXCELLENT_MARKS(val name: String) : MyScore()//分数优秀}

密封类的所有成员都继承本类MyScore ,但是允许个别成员拥有自己特殊属性如 EXCELLENT_MARKS 。

三、使用

密封类的代数数据类型

密封类与 when结合,使用 is 进行判断类型,跟枚举类相似

fun show() = when (myScore) {is MyScore.FAIL_A_GRADE -> "分数差"is MyScore.PASS_THE_MARK -> "分数及格"is MyScore.SCORE_WELL -> "分数良好"is MyScore.EXCELLENT_MARKS -> "分数优秀,name=${myScore.name}"}

密封类实例

当某个成员需要特殊属性的时候,用枚举就比较难实现这个需求,密封类就是为了解决这个问题而出现的。

如下实例:当我们想知道优秀学生的名字的时候,只用枚举去实现就不好实现

//密封类,所有成员都继承本类
//当某个成员需要特殊属性的时候,用枚举就比较难实现这个需求
sealed class MyScore {object FAIL_A_GRADE : MyScore()//分数差object PASS_THE_MARK : MyScore()//分数及格object SCORE_WELL : MyScore()//分数良好class EXCELLENT_MARKS(val name: String) : MyScore()//分数优秀}class Teachers(private val myScore: MyScore) {fun show() = when (myScore) {is MyScore.FAIL_A_GRADE -> "分数差"is MyScore.PASS_THE_MARK -> "分数及格"is MyScore.SCORE_WELL -> "分数良好"is MyScore.EXCELLENT_MARKS -> "分数优秀,name=${myScore.name}"}}//todo kotlin语言的密封类学习
fun main() {println(Teachers(MyScore.FAIL_A_GRADE).show())println(Teachers(MyScore.EXCELLENT_MARKS("kotlin")).show())}

输出:

分数差
分数优秀,name=kotlin

四、密封类与设计模式

1.状态模式

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为。状态模式将状态封装成独立的类,并将请求委托给当前的状态对象,从而实现状态的切换和行为的变化。

1.1kotlin实现

密封类可以表示一个有限的状态集合,而且可以在when表达式中进行完备的检查,不需要使用else分支。例如,假设有一个电灯类,它有两种状态:开和关,每种状态下可以执行不同的操作。可以用以下的代码来实现:

// 定义一个密封类表示状态
sealed class State {// 定义一个抽象方法表示操作abstract fun operate()
}// 定义一个开状态的子类,继承自State
class On : State() {// 重写操作方法,打印信息并切换到关状态override fun operate() {println("The light is on, turn it off.")Light.state = Off()}
}// 定义一个关状态的子类,继承自State
class Off : State() {// 重写操作方法,打印信息并切换到开状态override fun operate() {println("The light is off, turn it on.")Light.state = On()}
}// 定义一个电灯类,它有一个状态属性,初始为关状态
object Light {var state: State = Off()// 定义一个方法,根据当前状态执行操作fun switch() {state.operate()}
}// 测试代码
fun main() {// 创建一个电灯对象val light = Light// 调用switch方法,根据当前状态执行操作light.switch() // The light is off, turn it on.light.switch() // The light is on, turn it off.light.switch() // The light is off, turn it on.
}
1.2java实现

在java中,实现状态模式的一种方式是使用枚举类,因为枚举类也可以表示一个有限的状态集合,而且可以实现接口或抽象类,从而定义不同的行为。例如,用java实现上面的例子,可以用以下的代码:

// 定义一个接口表示状态
interface State {// 定义一个抽象方法表示操作void operate();
}// 定义一个枚举类表示状态,实现State接口
enum LightState implements State {// 定义两个枚举常量,分别表示开和关状态// 在每个枚举常量的构造器中,传入一个State对象,表示该状态下的行为ON(new State() {// 重写操作方法,打印信息并切换到关状态@Overridepublic void operate() {System.out.println("The light is on, turn it off.");Light.state = OFF;}}),OFF(new State() {// 重写操作方法,打印信息并切换到开状态@Overridepublic void operate() {System.out.println("The light is off, turn it on.");Light.state = ON;}});// 定义一个私有的State属性,表示该枚举常量对应的状态对象private final State state;// 定义一个私有的构造器,接收一个State对象作为参数,赋值给state属性private LightState(State state) {this.state = state;}// 定义一个公共的方法,调用state属性的operate方法public void operate() {state.operate();}
}// 定义一个电灯类,它有一个状态属性,初始为关状态
class Light {// 定义一个静态的LightState属性,表示电灯的状态,初始为OFFpublic static LightState state = LightState.OFF;// 定义一个方法,根据当前状态执行操作public void switch() {state.operate();}
}// 测试代码
public class Main {public static void main(String[] args) {// 创建一个电灯对象Light light = new Light();// 调用switch方法,根据当前状态执行操作light.switch(); // The light is off, turn it on.light.switch(); // The light is on, turn it off.light.switch(); // The light is off, turn it on.}
}

可以看出,使用kotlin的密封类实现状态模式的优点是:

  • 代码更简洁,不需要定义接口或抽象类,也不需要使用匿名内部类
  • 代码更安全,不需要担心在其他地方出现未知的状态,也不需要使用else分支处理默认情况
  • 代码更易读,可以清楚地看出状态之间的层次关系和转换逻辑

使用java的枚举类实现状态模式的优点是:

  • 代码更统一,不需要在不同的类中定义状态,也不需要使用对象来表示状态
  • 代码更高效,不需要创建多个状态对象,也不需要使用多态来调用操作方法

2. 访问者模式

访问者模式是一种行为型设计模式,它允许在不修改已有类的结构的情况下,定义作用于这些类的新操作。访问者模式将元素的结构和元素的操作分离,使得操作可以根据不同的元素类型而变化。

2.1kotlin实现

在kotlin中,可以使用密封类来实现访问者模式,因为密封类可以表示一个有限的元素集合,而且可以在when表达式中进行完备的检查,不需要使用else分支。例如,假设有一个表达式类,它有两种子类:数字和加法,每种子类都可以被访问者访问,执行不同的操作。可以用以下的代码来实现:

// 定义一个密封类表示表达式
sealed class Expr {// 定义一个抽象方法表示接受访问者的访问abstract fun <R> accept(visitor: Visitor<R>): R
}// 定义一个数字的子类,继承Expr类,有一个value属性表示数字的值data class Num(val value: Int) : Expr() {// 重写accept方法,调用访问者的visitNum方法,传入自己作为参数override fun <R> accept(visitor: Visitor<R>): R {return visitor.visitNum(this)}}// 定义一个加法的子类,继承Expr类,有两个Expr属性表示左右操作数data class Sum(val left: Expr, val right: Expr) : Expr() {// 重写accept方法,调用访问者的visitSum方法,传入自己作为参数override fun <R> accept(visitor: Visitor<R>): R {return visitor.visitSum(this)}}// 定义一个访问者接口,泛型参数R表示访问的结果类型interface Visitor<R> {// 定义一个访问数字的方法,接收一个Num对象作为参数,返回一个R类型的结果fun visitNum(num: Num): R// 定义一个访问加法的方法,接收一个Sum对象作为参数,返回一个R类型的结果fun visitSum(sum: Sum): R}// 定义一个求值的访问者类,实现Visitor接口,泛型参数为Intclass EvalVisitor : Visitor<Int> {// 重写访问数字的方法,返回数字的值override fun visitNum(num: Num): Int {return num.value}// 重写访问加法的方法,返回左右操作数的求值结果的和override fun visitSum(sum: Sum): Int {return sum.left.accept(this) + sum.right.accept(this)}}// 定义一个打印的访问者类,实现Visitor接口,泛型参数为Stringclass PrintVisitor : Visitor<String> {// 重写访问数字的方法,返回数字的字符串表示override fun visitNum(num: Num): String {return num.value.toString()}// 重写访问加法的方法,返回加法的字符串表示,用括号括起来override fun visitSum(sum: Sum): String {return "(${sum.left.accept(this)} + ${sum.right.accept(this)})"}}// 测试代码fun main() {// 创建一个表达式对象,表示1 + (2 + 3)val expr = Sum(Num(1), Sum(Num(2), Num(3)))// 创建一个求值的访问者对象val evalVisitor = EvalVisitor()// 创建一个打印的访问者对象val printVisitor = PrintVisitor()// 调用表达式的accept方法,传入求值的访问者,打印求值的结果println(expr.accept(evalVisitor)) // 6// 调用表达式的accept方法,传入打印的访问者,打印表达式的字符串表示println(expr.accept(printVisitor)) // (1 + (2 + 3))}

可以看出,使用kotlin的密封类实现访问者模式的优点是:

  • 代码更简洁,不需要定义抽象方法或接口,也不需要使用类型转换或类型检查
  • 代码更安全,不需要担心在其他地方出现未知的表达式类型,也不需要使用else分支处理默认情况
  • 代码更易读,可以清楚地看出表达式之间的层次关系和访问者的操作逻辑
2.2 java实现
// 抽象元素
interface Animal {void accept(Visitor visitor); // 接受一个抽象访问者
}// 具体元素Lion
class Lion implements Animal {@Overridepublic void accept(Visitor visitor) {visitor.visit(this); // 调用具体访问者对自己进行操作}public String roar() {return "Roar!";}
}// 具体元素Tiger
class Tiger implements Animal {@Overridepublic void accept(Visitor visitor) {visitor.visit(this); // 调用具体访问者对自己进行操作}public String growl() {return "Growl!";}
}// 具体元素Elephant
class Elephant implements Animal {@Overridepublic void accept(Visitor visitor) {visitor.visit(this); // 调用具体访问者对自己进行操作}public String trumpet() {return "Trumpet!";}
}// 抽象访问者
interface Visitor {void visit(Lion lion); // 访问具体元素Lionvoid visit(Tiger tiger); // 访问具体元素Tigervoid visit(Elephant elephant); // 访问具体元素Elephant
}// 具体访问者Feed
class Feed implements Visitor {@Override public void visit(Lion lion) { System.out.println("Feed the lion with meat.");} @Override public void visit(Tiger tiger) { System.out.println("Feed the tiger with chicken.");} @Override public void visit(Elephant elephant) { System.out.println("Feed the elephant with banana.");} 
}// 具体访问者Observe
class Observe implements Visitor { @Override public void visit(Lion lion) { System.out.println("Observe the lion: " + lion.roar());} @Override public void visit(Tiger tiger) { System.out.println("Observe the tiger: " + tiger.growl());} @Override public void visit(Elephant elephant) { System.out.println("Observe the elephant: " + elephant.trumpet());}  
}// 具体访问者Train
class Train implements Visitor {  @Override  public void visit(Lion lion) {  System.out.println("Train the lion to jump through a hoop.");  }  @Override  public void visit(Tiger tiger) {  System.out.println("Train the tiger to stand on a ball.");  }  @Override  public void visit(Elephant elephant) {  System.out.println("Train the elephant to sit on a stool.");  }   
}  // 对象结构类Zooclass Zoo {private List<Animal> animals = new ArrayList<>();// 添加一个新动物   
public void add(Animal animal) {   animals.add(animal);   
}   // 移除一个已有动物   
public void remove(Animal animal) {   animals.remove(animal);   
}   // 接受一个抽象访问者,并将所有动物传递给它进行处理    
public void accept(Visitor visitor) {    for (Animal animal : animals) {    animal.accept(visitor);    }    
}   
}

测试代码:

public class Test {public static void main(String[] args) {Zoo zoo = new Zoo();zoo.add(new Lion());zoo.add(new Tiger());zoo.add(new Elephant());Visitor feed = new Feed();Visitor observe = new Observe();Visitor train = new Train();zoo.accept(feed);zoo.accept(observe);zoo.accept(train);}
}

运行测试代码并显示输出结果:

Feed the lion with meat.
Feed the tiger with chicken.
Feed the elephant with banana.
Observe the lion: Roar!
Observe the tiger: Growl!
Observe the elephant: Trumpet!
Train the lion to jump through a hoop.
Train the tiger to stand on a ball.
Train the elephant to sit on a stool.

五、与final类对比

特性密封类final类
可继承性部分可继承,只能被指定的类继承不可继承
受保护成员或虚成员不允许,因为密封类的子类必须是密封类或final类允许,因为final类没有子类
抽象性允许,因为密封类可以是抽象的或具体的不允许,因为抽象类必须被继承
相似之处都是限制类的继承,都不能声明为抽象的,都可以继承别的类或接口都是限制类的继承,都不能声明为抽象的,都可以继承别的类或接口
不同之处可以指定哪些类可以作为其子类,可以实现多态性,可以用于一些特定的设计模式不能有任何子类,不能实现多态性,不能用于一些特定的设计模式
优点可以保证封装性和多态性,可以提高代码的可读性和可维护性,可以避免不必要的继承或实现可以保证封装性和不变性,可以提高代码的执行效率,可以避免类的滥用
缺点可能增加代码的复杂度和冗余,可能限制类的扩展性和灵活性,可能与一些框架或库不兼容可能增加代码的耦合度和僵化度,可能限制类的扩展性和灵活性,可能与一些框架或库不兼容
应用场景可以用于实现一些特定的设计模式,例如状态模式、策略模式、访问者模式等,这些模式需要明确地定义一组有限的子类或实现类可以用于实现一些不需要继承的类,例如工具类、常量类、单例类等,这些类需要保证其不变性和唯一性


六、应用

如果说,我们一个需求,控制档位,有两种模式,一种是inch 一种是mm。怎么表达?

我们想到是两个数组一一对应,如果java写就是枚举。

public class Test {public static void main(String[] args) {System.out.println("根据英文描述获取中文描述:" + ColorEnum.getDescriptionByCode(ColorEnum.YELLOW.getCode()));System.out.println("根据输入字符获取中文描述(有):" + ColorEnum.getDescriptionByCode("RED"));System.out.println("根据输入字符获取中文描述(无):" + ColorEnum.getDescriptionByCode("PURPLE"));}
}enum ColorEnum {YELLOW("YELLOW", "黄色"),WHITE("WHITE", "白色"),GREEN("GREEN", "绿色"),BLUE("BLUE", "蓝色"),RED("RED", "红色");//枚举标识码(中文描述)private final String description;//这个必须定义,且成员变量的类型及个数必须对应于上边枚举的定义//枚举标识码(英文描述)private final String code;ColorEnum(String code, String description) {this.code = code;this.description = description;}public String getCode() {return code;}public String getDescription() {return description;}public static String getDescriptionByCode(String code) {for (ColorEnum value : ColorEnum.values()) {if (value.getCode().equals(code)) {return value.getDescription();}}return null;}
}执行结果:
根据英文描述获取中文描述:黄色
根据输入字符获取中文描述(有):红色
根据输入字符获取中文描述(无):null

那么kotlin怎么写:

用data数据类+密封类

sealed class OrderStatus {abstract val orderId: Stringdata class Pending(override val orderId: String) : OrderStatus()data class Shipped(override val orderId: String, val trackingNumber: String) : OrderStatus()data class Delivered(override val orderId: String, val deliveryDate: String) : OrderStatus()object Cancelled : OrderStatus()fun getDescription(): String {return when (this) {is Pending -> "Order $orderId is pending"is Shipped -> "Order $orderId has been shipped with tracking number $trackingNumber"is Delivered -> "Order $orderId has been delivered on $deliveryDate"Cancelled -> "Order $orderId has been cancelled"}}
}fun main() {val pendingOrder = OrderStatus.Pending("12345")val shippedOrder = OrderStatus.Shipped("67890", "XYZ123")val deliveredOrder = OrderStatus.Delivered("23456", "2023-09-25")val cancelledOrder = OrderStatus.Cancelledprintln(pendingOrder.getDescription())println(shippedOrder.getDescription())println(deliveredOrder.getDescription())println(cancelledOrder.getDescription())
}

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

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

相关文章

SpringBoot 项目如何使用 pageHelper 做分页处理 (含两种依赖方式)

分页是常见大型项目都需要的一个功能&#xff0c;PageHelper是一个非常流行的MyBatis分页插件&#xff0c;它支持多数据库分页&#xff0c;无需修改SQL语句即可实现分页功能。 本文在最后展示了两种依赖验证的结果。 文章目录 一、第一种依赖方式二、第二种依赖方式三、创建数…

Virtuoso服务在centos中自动停止的原因分析及解决方案

目录 前言1. 问题背景2. 原因分析2.1 终端关闭导致信号12.2 nohup命令的局限性 3. 解决方案3.1 使用 screen 命令保持会话3.2 使用 tmux 作为替代方案3.3 使用系统服务&#xff08;systemd&#xff09; 4. 其他注意事项4.1 网络配置4.2 日志监控 结语 前言 在使用Virtuoso作为…

Transformer 的可视化解释

Transformer 的可视化解释&#xff1a;了解 LLM Transformer 模型如何与交互式可视化配合使用 部署 Nodejs version > 20.0 git clone https://github.com/poloclub/transformer-explainer.git cd transformer-explainer npm install npm run dev# fix: cnpm install --pl…

AD9854 为什么输出波形幅度受限??

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

lambda 自调用递归

从前序与中序遍历序列构造二叉树 官方解析实在是记不住&#xff0c;翻别人的题解发现了一个有意思的写法 class Solution { public:TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {auto dfs [](auto&& dfs, auto&&…

Pandas和matplotlib实现同期天气温度对比

目录 1、下载近两年的天气Excel数据 2、pandas加载Excel 3、将时间作为索引 4、按日计算最值、均值 5、选取近两年同期温度数据 6、同期温度曲线对比,共享y轴 1、下载近两年的天气Excel数据 一个免费的天气数据下载网址:METAR北京(机场)历史天气 (rp5.ru) 选择”北京天…

centos 7.9安装k8s

前言 Kubernetes单词来自于希腊语&#xff0c;含义是领航员&#xff0c;生产环境级别的容器编排技术&#xff0c;可实现容器的自动部署扩容以及管理。Kubernetes也称为K8S&#xff0c;其中8代表中间8个字符&#xff0c;是Google在2014年的开源的一个容器编排引擎技术&#xff…

一文读懂SpringCLoud

一、前言 只有光头才能变强 认识我的朋友可能都知道我这阵子去实习啦&#xff0c;去的公司说是用SpringCloud(但我觉得使用的力度并不大啊~~)… 所以&#xff0c;这篇主要来讲讲SpringCloud的一些基础的知识。(我就是现学现卖了&#xff0c;主要当做我学习SpringCloud的笔记吧&…

【JPCS出版】第二届应用统计、建模与先进算法国际学术会议(ASMA2024,9月27日-29)

第二届应用统计、建模与先进算法国际学术会议 2024 2nd International Conference on Applied Statistics, Modeling and Advanced Algorithms&#xff08;ASMA2024&#xff09; 会议官方 会议官网&#xff1a;www.icasma.org 2024 2nd International Conference on Applied …

Moveit2与gazebo联合仿真:添加摄像头传感器

1.代码更新修改 1.1 添加物理关节 如图&#xff0c;在原有机械臂的基础上添加camera_link和base_camera_joint作为传感器的几何属性 对应的xml代码如下 <link name"${prefix}camera_link"><collision><geometry><box size"0.01 0.1 0.05&…

【Python】练习:控制语句(二)第4关

第4关&#xff1a;控制结构综合实训 第一题第二题&#xff08;※&#xff09;第三题&#xff08;※&#xff09;第四题&#xff08;※&#xff09;第五题&#xff08;※&#xff09;第六题&#xff08;※&#xff09; 第一题 #第一题def rankHurricane(velocity):#请在下面编写…

毫米波雷达预警功能 —— 盲区检测(BSD)预警

文档声明&#xff1a; 以下资料均属于本人在学习过程中产出的学习笔记&#xff0c;如果错误或者遗漏之处&#xff0c;请多多指正。并且该文档在后期会随着学习的深入不断补充完善。感谢各位的参考查看。 笔记资料仅供学习交流使用&#xff0c;转载请标明出处&#xff0c;谢谢配…

MySQL高阶1875-将工资相同的雇员分组

目录 题目 准备数据 分析数据 题目 编写一个解决方案来获取每一个被分配到组中的雇员的 team_id 。 返回的结果表按照 team_id 升序排列。如果相同&#xff0c;则按照 employee_id 升序排列。 这家公司想要将 工资相同 的雇员划分到同一个组中。每个组需要满足如下要求&a…

Lichee NanoKVM基本使用环境

Lichee NanoKVM基本使用环境 本文章主要记录一些自己在初期的使用&#xff0c;以及自己的一些经验 &#xff0c;非常感谢sipeed NanoKVM官方使用教程 外观&#xff08;博主自己的是lite版本&#xff0c;非常感谢sipeed&#xff09; Lichee NanoKVM 是基于 LicheeRV Nano 的 I…

msvcp120dll丢失问题的相关分享,4种靠谱的修复msvcp120dll的方法

在你启动某个软件或游戏的过程中&#xff0c;如果屏幕上突然出现一条提示说“msvcp120.dll文件缺失”这时候请不要紧张&#xff0c;要解决这个问题还是比较简单的。msvcp120.dll 是一个关键的系统文件&#xff0c;属于 Microsoft Visual C 可再发行组件包的一部分。它包含了许多…

电影《祝你幸福!》观后感

上周看了电影《祝你幸福&#xff01;》&#xff0c;虽然讲述的是一个悲伤的故事&#xff0c;但自己看来&#xff0c;其实更是一个人遭遇创伤后&#xff0c;如何自己走出来的过程&#xff0c;尤其重大精神创伤。另外作为本部电影的主角&#xff0c;另一个身份是律师&#xff0c;…

编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MSVC版)

相邻你找了很多博文&#xff0c;都没有办法。现在终于找到了正宗。 参考 GitHub - thecodemonkey86/qt_mysql_driver: Typical symptom: QMYSQL driver not loaded. Solution: get pre-built Qt SQL driver plug-in required to establish a connection to MySQL / MariaDB u…

小红书本地生活,要生活还是生意?

8月&#xff0c;沉寂许久的小红书本地生活突然动作频频。8月23日&#xff0c;小红书新增本地生活服务商管理规范和入驻规则&#xff0c;10天后正式宣布开放全国49座城市的餐饮团购类目&#xff0c;并将技术服务费从0.6%最新调整至2.6%&#xff0c;49城餐饮商家自此打通门店团购…

python开发子域名扫描器

python开发子域名扫描器 1. 前言2. 子域名扫描器开发2.1. 第一阶段2.2. 第二阶段2.3. 第三阶段2.4. 第四阶段 3. 总结 1. 前言 不想对内容解释过多了&#xff0c;自行去百度搜索相关的参数怎么使用的吧。对于编写工具基本上用到的无非就是多线程、请求等等这些&#xff0c;很多…

【Elasticsearch】-spring boot 依赖包冲突问题

<dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.17.24</version></dependency> 在pom的配置中&#xff0c;只引入了elasticsearch-7.17.24 &#xff0c;但实际上会同时…