当前位置: 首页 > news >正文

Kotlin程序设计 扩展篇(一)

image-20240113154815774

Kotlin程序设计(扩展一)

**注意:**开启本视频学习前,需要先完成以下内容的学习:

  • 请先完成《Kotlin程序设计》视频教程。
  • 请先完成《JavaSE》视频教程。

Kotlin在设计时考虑到了与Java的互操作性,现有的Java代码可以自然地调用Kotlin代码,而Kotlin代码也可以轻松兼容Java的调用。在本扩展篇中,我们会讲解如何通过Kotlin调用Java代码。

Kotlin调用Java

我们先从最基本的内容说起,现在需要让Kotlin与Java互相兼容,并不是直接就可以使用的,我们还要遵循某些约定才可以使得Java兼容Kotlin的语法。

类的定义和使用

在Java中,最关键的就是类,我们来看看如何在Kotlin中进行使用。

我们在Java中定义的类型,可以非常轻松地被Kotlin使用,比如下面这个由Java语言定义的类型:

public class Student {int age;String name;
}

在Kotlin中,我们可以直接使用这个类,就像是在Kotlin中定义的那样:

fun main() {val student: Student = Student()   //直接使用Java中的类型,无缝衔接student.name = "小明"println(student.name)  //这里得到的Java中的String类型,可以直接当做Kotlin中的使用
}

以及Kotlin中我们提到的一些基本类型,都可以与Java中的基本类型互相转换:

fun main() {val student = Student()val age: Int = student.age   //Java中的int/Integer对应了Kotlin中的Int
}

几乎Java中所有基本类型在Kotlin中都存在对应的类型,所以说直接转换为Kotlin支持的基本类型也是可以的。

包括我们在类中定义的方法,也可以在Kotlin中被当做函数使用:

public class Student {String name;public void hello() {System.out.println("大家好,我叫" + name);}
}
fun main() {val student = Student()student.name = "小明"student.hello()   //函数调用
}

注意,如果方法的返回类型是void,那么它对应的就是Kotlin中的Unit类型。

包括在Java中定义的构造方法,也可以被Kotlin当做构造函数使用,因为它们的语法其实差不多,可以很轻松完成兼容:

public class Student {String name;public Student(String name) {this.name = name;}
}
fun main() {val student = Student("小明")
}

可以看到,这些内容几乎是没有多少学习成本的,包括在Java类中定义的静态内容:

public class Student {public static void test() {System.out.println("我是测试静态函数");}
}

这些静态属性就像使用Kotlin中的伴生对象一样,可以直接通过类名进行调用,这跟Java中是一样的:

fun main() {Student.test()
}

还有,由于Kotlin与Java中的关键字存在差异,我们在Java中定义的某些属性名称可能会成为Kt的关键字:

import java.io.InputStream;
public class Student {InputStream in;  //Java中没有问题,因为in不是关键字
}
fun main() {val student = Student()//在Kotlin中,由于in是关键字,因此我们需要对其进行转义来消除冲突//使用``字符来完成转义student.`in` = FileInputStream("C://")
}

包括Java中的可变参数,也是可以直接兼容的:

public class Student {public void test(String... args) {}
}

image-20240113205404890

我们也可以直接继承Java中提供的类型:

public class Student {}
class ArtStudent: Student()   //语法与之前是一样的

在后续的学习中,我们再来继续认识更多高级的内容。

Getter和Setter

在Kotlin基础教程中我们说到,类中的成员属性可以具有自己的Getter和Setter函数,比如:

class Student {var name: String = ""get() = fieldset(value) {field = value}
}

这样我们就可以实现对于这个变量赋值和获取的进一步控制,比如我们希望在赋值时打印内容:

var name: String = ""get() = fieldset(value){println("我被赋值了!")   //由于get和set本质上编译后是函数,因此可以自定义field = value}

而我们知道,在Java中,一个类的属性并不能像这样去编写:

public class Student {String name;   //只能定义一个变量,非常简单
}

我们可以对Java中的这个属性进行封装,使得其支持像Kotlin中那样存在Getter和Setter函数:

public class Student {private String name;   //将name属性private掉public String getName() {  //自定义Get和Set方法设置name属性return name;}public void setName(String name) {this.name = name;}
}
fun main() {val student = Student()student.name = "小明"println(student.name)
}

这样编写之后,我们同样可以在Kotlin中直接使用对应属性的名称进行访问,但是这本质上是通过其Get和Set函数来完成的,在获取属性时,会调用getName()方法得到对应的结果,设置同理。

注意:这个Get和Set必须遵循命名规则,比如这里我们要为name属性添加Getter方法,那么必须要命名为get + Name这样的名称,来表示对name属性的命名,必须以get开头,而Setter必须以set开头。

如果返回值类型是一个Boolean类型,那么Getter方法名称需要以is开头,而Setter同上。

注意,由于此时name属性由于存在访问权限控制,无法被外部访问,如果我们去掉Setter或是Getter函数,将导致变量只能被赋值或是不可用,比如去掉set方法后:

image-20240113161702594

注意: 如果直接去掉Getter方法,无论是否保留Setter方法,都会导致这个变量不可用,因为Kotlin不支持仅set-only属性。

空安全处理

由于在Java中的任何引用类型值都可能是null,这使得Kotlin对来自Java的对象进行空安全检测不太方便。因此,对于Java声明的类型会在Kotlin中以特定方式处理,我们称为平台类型。对于这种类型,空检查是放宽的,因此它们的安全保证与Java相同,也就是说部分情况下不会进行空安全检查。

比如下面这个例子:

public class Student {String name;   //默认情况下name属性的值就是null
}
fun main() {val student = Student()//此时name在Kotlin中为平台类型,不会进行空安全检查,这里可以编译通过println(student.name.uppercase())
}

很明显,上面的代码出现了空指针异常,因为这里没有进行任何的空安全检查。

对于这种平台类型,IDEA会给我们明确指出,比如这里的name属性时String!类型的,它表示这个类型可能是SrtingString?的其中一种:

image-20240113163709872

我们在接受这个属性的时候,由于其特殊性,也可以使用两种:

fun main() {val student = Student()val name: String = student.name  //直接使用不可空类型接受,但是可能会出错val name2: String? = student.name  //直接使用可空类型接受test(student.name)  //函数同样适用此规则
}fun test(str: String) {  }

如果我们使用了一个不可空类型接受到来自Java的null值,会直接得到一个空指针异常,这可以防止Kotlin的不可空变量持有空值,包括传递函数参数时也同样适用,总的来说,编译器在尽最大努力防止空值在Kotlin程序中传播。

注意,在某些情况下,持有可空注解的Java类型不会表现为平台类型,比如:

public class Student {@NotNull String name;  //由JetBrains提供的注解
}

image-20240113164828898

这些注解包括:

  • JetBrains(来自org.jetbrains.annotations包下的@@Nullable@NotNull
  • JSpecify(org.jspecify.nullness
  • Android(com.android.annotationsandroid.support.annotations
  • JSR-305(javax.annotation
  • FindBugs(edu.umd.cs.findbugs.annotations
  • Eclipse(org.eclipse.jdt.annotation
  • Lombok(lombok.NonNull
  • RxJava 3(io.reactivex.rxjava3.annotations

同样的,对于一些泛型类,也存在一些空类型检查问题,这里以List为例:

public class Student {List<String> exams;
}
fun main() {val student = Student()val exams1: MutableList<String?>? = student.exams  //支持多种方式val exams2: MutableList<String?> = student.examsval exams3: List<String?>? = student.exams...
}

可以看到,在我们使用Java中提供的List时,会得到:

image-20240113165654653

这里的(Mutable)List<String!>!包含了很多信息,我们依次来解读一下:

  • 首先Mutable表示这个List可以是可变的也可以是不可变的,因为在Java中并没有明确划分可变或是不可变的数组。
  • 然后这里的类型参数String和List都带有!表示他们都可以是可空类型也可以是不可空类型。

我们同样可以使用非空注解来提醒编译器这里一定不会为null防止被认定为平台类型:

public class Student {@NotNull List<String> exams;
}

以及在Java中的数组类型,对应的就是Kotlin中的Array类型:

public class Student {String[] exams;
}

image-20240113171513951

由于数组在Java支持协变(这与Kotlin存在不同)因此,这里我们使用Java中的数组时,可以将其当做一个抗变或是协变的String类型进行使用:

fun main() {val student = Student()val exams1: Array<String>  = student.examsval exams2: Array<out String?>  = student.examsval exams3: Array<out String?>?  = student.exams
}

这里的到的Array可以是可空也可以是不可空,里面的类型参数String同样可以是可空或是不可空,并且可以是协变也可以是抗变的。

类型对照表

前面我们提到,在Kotlin中存在Java中相应的基本类型,我们在使用Java提供的类型时,可以直接转换使用:

Java类型Java包装类型Kotlin类型
bytejava.lang.Bytekotlin.Byte
shortjava.lang.Shortkotlin.Short
intjava.lang.Integerkotlin.Int
longjava.lang.Longkotlin.Long
charjava.lang.Characterkotlin.Char
floatjava.lang.Floatkotlin.Float
doublejava.lang.Doublekotlin.Double
booleanjava.lang.Booleankotlin.Boolean

注意,虽然Java类型可以映射到Kotlin对应的类型,但是平台类型性质依然保留:

public class Student {Integer age;
}

image-20240113180605251

可以看到,对于Java中的包装类型Integer,这里虽然可以直接转换为Int类型,但是它依然可以是Int?或是Int这两种类型。只不过,对于Java中的基本类型来说,由于不存在null这种结果,因此我们可以安全的将其当做不可空类型使用:

public class Student {int age;
}

image-20240113181910862

除了这些基本类型之外,实际上Kotlin中还有很多其他类型也可以直接映射:

Java类型Kotlin类型
java.lang.Objectkotlin.Any!
java.lang.Cloneablekotlin.Cloneable!
java.lang.Comparablekotlin.Comparable!
java.lang.Enumkotlin.Enum!
java.lang.annotation.Annotationkotlin.Annotation!
java.lang.CharSequencekotlin.CharSequence!
java.lang.Stringkotlin.String!
java.lang.Numberkotlin.Number!
java.lang.Throwablekotlin.Throwable!

集合类型在Kotlin中可以是只读的或可变的,因此Java的集合映射如下(此表中的所有Kotlin类型都定义在kotlin.collections包中)

Java类型Kotlin只读类型Kotlin可变类型转换平台类型
Iterator<T>Iterator<T>MutableIterator<T>(Mutable)Iterator<T>!
Iterable<T>Iterable<T>MutableIterable<T>(Mutable)Iterable<T>!
Collection<T>Collection<T>MutableCollection<T>(Mutable)Collection<T>!
Set<T>Set<T>MutableSet<T>(Mutable)Set<T>!
List<T>List<T>MutableList<T>(Mutable)List<T>!
ListIterator<T>ListIterator<T>MutableListIterator<T>(Mutable)ListIterator<T>!
Map<K, V>Map<K, V>MutableMap<K, V>(Mutable)Map<K, V>!
Map.Entry<K, V>Map.Entry<K, V>MutableMap.MutableEntry<K,V>(Mutable)Map.(Mutable)Entry<K, V>!

以及数组的映射如下,基本类型的数组会被直接映射为基本类型专用的Array类型:

Java类型Kotlin类型
int[]kotlin.IntArray!
String[]kotlin.Array<(out) String>!

注意,在Java中,这些类型可能存在一些静态属性,如果我们需要调用对应的静态属性,需要使用Java中类型的名称进行调用:

//在Integer中定义的静态方法
public static int parseInt(String s) throws NumberFormatException {return parseInt(s,10);
}
fun main() {Integer.parseInt("666")  //需要使用原本的名称,而不是转换之后的Int
}

泛型转换

Kotlin的泛型与Java型有点不同,当将Java类型导入Kotlin时,将完成以下转换:

  • Java的通配符转换:
    • Foo<? extends Bar>成为Foo<out Bar!>!
    • Foo<? super Bar>成为Foo<in Bar!>!
public class Student {List<? extends Number> data;  //此时泛型上界为NumberList<? super Integer> data2;  //此时泛型下界为Integer
}

当这些类型在Kotlin中使用时,会自动被划分为协变或抗变类型:

fun main() {val student = Student()//Java中的泛型上界对应Kotlin的协变类型val data: MutableList<out Number> = student.data//Java中的泛型下界对应Kotlin的抗变类型val data2: MutableList<in Int> = student.data2
}

由于在Kotlin中对in和out进行了严格的使用限制,因此无法像Java那样随意使用。

  • Java的原始类型被转换为星形投影:
    • List当做List<*>!也就是List<out Any?>!
public class Student {List data;   //对List的原始使用
}
fun main() {val student = Student()//在Kotlin中直接以Any?作为实际类型使用,因为没有明确具体类型val data: MutableList<Any?>? = student.data
}

与Java一样,Kotlin的泛型不会在运行时保留,也就是说对象不会带有任何实际类型参数的信息,详情请见基础篇。

运算符重载

由于Java不支持运算符重载,我们无法通过关键字支持像Kotlin这样的运算符重载,但是,只要符合我们前面所说的那些运算符重载函数名称的方法,依然可以作为运算符重载函数使用:

public class Student {public Student plus(Student other) {return this;}
}

可以看到,以上代码与Kotlin中+运算符重载函数的定义相同,满足规范,因此,在Kotlin中,可以直接支持使用:

fun main() {var student = Student()student = student + student
}

异常检查

在Kotlin中,所有异常都不会主动进行检查,这意味着编译器不会强迫您捕获任何异常。因此,当您调用声明了异常的Java方法时,Kotlin不会强制要求进行捕获:

public class Student {public void test() throws IOException {}
}
fun main() {var student = Student()student.test()
}

Object类型

当Java对象在Kotlin中使用时,Object类型的所有引用都会变成Any类型。由于Any类型不是特定于某一个平台的,考虑到对其他语言的兼容性,因此,它只声明toString()``hashCode()equals()函数作为其成员,而在Java中,Object存在很多其他的成员方法:

public final native Class<?> getClass();
public final native void notify();
public final native void notifyAll();
...

如果需要让Object类中的其他成员方法可用,可以像下面这样:

fun main() {val student = Student()//将student类型转换为Object再调用其(student as Object).wait()
}

不过,在Kotlin中不鼓励使用wait()notify()等线程相关方法,使用JUC中提供的类型效果更佳(详情请见Java JUC篇视频教程)

如果我们要获取某个类的Class对象:

fun main() {val student = Student()val clazz: Class<Student> = student.javaClass  //使用.javaClass获取到对应的Java类对象
}

函数式接口

Kotlin支持Java的SAM转换,只要是Java中满足要求的函数式接口,都可以开箱即用:

@FunctionalInterface
public interface Runnable {public abstract void run();
}
fun main() {//使用Java中的Runnable接口val runnable: Runnable = Runnable {println("Hello World")}
}

包括我们在函数中一样可以像这样使用:

import java.util.concurrent.ThreadPoolExecutorfun main() {val executor = ThreadPoolExecutor()// Java方法定义: void execute(Runnable command)executor.execute { println("This runs in a thread pool") }
}

Java调用Kotlin

前面我们介绍了Kotlin如何调用现成的Java代码,我们接着来看Java如何调用Kotlin代码。由于Java和Kotlin之间存在某些差异,在将Kotlin代码集成到Java中时需要注意很多东西。

对象属性

在Kotlin中定义的类型,到了Java中依然可以直接创建其对象:

class Student(var name: String)
public static void main(String[] args) {Student student = new Student("小明");   //Kt构造函数就是构造方法
}

只不过,对于类的属性,由于Kotlin中本质是以get和set函数的形式存在的,因此,我们只能使用对应的Getter和Setter方法来进行调用:

public static void main(String[] args) {Student student = new Student("小明");student.getName();student.setName("大明");   //set方法仅在属性为var时可用
}

如果实在是需要在Java中像使用普通变量那样,我们可以添加一个特殊的注解使其支持:

class Student(@JvmField var name: String)

包括懒加载属性也支持:

class Student {lateinit var name: String
}
public static void main(String[] args) {Student student = new Student("小明");student.name = "";
}

当然,这个属性不得是 openoverrideconst 其中一种,也不能是委托属性。

同时,由于Java中不存在空类型处理,因此,在Kotlin中定义的无论是否为可空类型都可以在Java中直接使用:

class Student {var name: String? = null
}
public static void main(String[] args) {Student student = new Student();student.getName().toUpperCase();   //直接空指针异常
}

静态属性

如果是Kotlin文件中直接编写的顶层定义,可以当做特定文件的静态属性来使用:

fun test() {println("Hello World")
}

在编译之后,它本质上就是一个Java中的静态方法,而对应类的名称就是源文件名称+Kt,这里Main.kt对应的名称就是MainKt了:

public static void main(String[] args) {MainKt.test();
}

我们也可以使用注解来明确生成的Java字节码文件名称:

@file:JvmName("LBWNB")
public static void main(String[] args) {LBWNB.test();
}

对于伴生对象以及单例对象,在Java中使用起来可能会有些别扭:

class Student {companion object {fun test() {}}
}object Test {fun hello() {}
}
public static void main(String[] args) {Student.Companion.test();Test.INSTANCE.hello();
}

这并不是我们希望的样子,在Kotlin中我们可以直接使用Student.的形式来直接调用,而在Java中却有一些出入,我们可以为这些函数添加@JvmStatic注解来完成:

class Student {companion object {@JvmStatic fun test() {}}
}

对于伴生对象中的字段,我们也可以为其添加@JvmField注解来使得其可以直接使用,这会在编译时使得此函数作为Student的静态属性存在:

public static void main(String[] args) {Student.test();
}

同样的,对于伴生对象中的属性来说,我们也像上一小节那样添加@JvmField注解:

class Student {companion object {@JvmField var name: String = ""}
}
public static void main(String[] args) {Student.name = "";   //此时name就是Student的静态属性
}

相关文章:

Kotlin程序设计 扩展篇(一)

Kotlin程序设计&#xff08;扩展一&#xff09; **注意&#xff1a;**开启本视频学习前&#xff0c;需要先完成以下内容的学习&#xff1a; 请先完成《Kotlin程序设计》视频教程。请先完成《JavaSE》视频教程。 Kotlin在设计时考虑到了与Java的互操作性&#xff0c;现有的Ja…...

星环科技基于第五代英特尔®至强®可扩展处理器的分布式向量数据库解决方案重磅发布

12月15日&#xff0c;2023 英特尔新品发布会暨 AI 技术创新派对上&#xff0c;星环科技基于第五代英特尔至强可扩展处理器的Transwarp Hippo分布式向量数据库解决方案重磅发布。该方案利用第五代英特尔至强可扩展处理器带来的强大算力&#xff0c;实现了约 2 倍的代际性能提升&…...

一体化运维的发展趋势与未来展望

随着信息技术的迅猛发展&#xff0c;企业的IT系统已经从单一的、孤立的应用转变为多元化、复杂化的系统集群。云计算、大数据、物联网等前沿技术的广泛应用&#xff0c;使得企业的IT运维面临着前所未有的挑战。在这样的背景下&#xff0c;一体化运维作为一种新型的运维模式&…...

科技云报道:金融大模型落地,还需跨越几重山?

科技云报道原创。 时至今日&#xff0c;大模型的狂欢盛宴仍在持续&#xff0c;而金融行业得益于数据密集且有强劲的数字化基础&#xff0c;从一众场景中脱颖而出。 越来越多的公司开始布局金融行业大模型&#xff0c;无论是乐信、奇富科技、度小满、蚂蚁这样的金融科技公司&a…...

C语言入门到精通之练习34:求100之内的素数

题目&#xff1a;求100之内的素数。 程序分析&#xff1a;质数&#xff08;素数&#xff09;酵母素数&#xff0c;有无限个。一个大于1的自然数&#xff0c;除了1和它本身外&#xff0c;不能被其他自然数整除。 代码如下&#xff1a; #include <stdio.h># #include &l…...

Qt采集本地摄像头推流成rtsp/rtmp(可网页播放/支持嵌入式linux)

一、功能特点 支持各种本地视频文件和网络视频文件。支持各种网络视频流&#xff0c;网络摄像头&#xff0c;协议包括rtsp、rtmp、http。支持将本地摄像头设备推流&#xff0c;可指定分辨率和帧率等。支持将本地桌面推流&#xff0c;可指定屏幕区域和帧率等。自动启动流媒体服…...

Oracle按日周月年自动分区

目录 1、分区键 2、初始分区 3、周月年自动分区 4、按日自动分区表建表语句 与普通建表语句相比&#xff0c;分区表多了一些分区信息&#xff1b; 1、分区键 以下面销售明细表为例&#xff0c;以data_dt为分区键&#xff0c;NUMTODSINTERVAL(1, day) 按日分区 PARTITION …...

单元测试、模块测试、web接口测试

单元测试与模块测试 什么是“单元测试”、“模块测试”&#xff1f; 然而在功能的实现代码中并没有“单元”&#xff0c;也没有“模块”&#xff1b;只有函数、类和方法。先来分别看看它们 的定义&#xff1a; 单元测试&#xff08;Unit testing&#xff09;&#xff0c;是指…...

DAY10_SpringBoot—SpringMVC重定向和转发RestFul风格JSON格式SSM框架整合Ajax-JQuery

目录 1 SpringMVC1.1 重定向和转发1.1.1 转发1.1.2 重定向1.1.3 转发练习1.1.4 重定向练习1.1.5 重定向/转发特点1.1.6 重定向/转发意义 1.2 RestFul风格1.2.1 RestFul入门案例1.2.2 简化业务调用 1.3 JSON1.3.1 JSON介绍1.3.2 JSON格式1.3.2.1 Object格式1.3.2.2 Array格式1.3…...

刘润-进化的力量2 一刷 笔记

安全感来自确定性&#xff0c;但机会藏在不确定性中 安全感来自确定性&#xff0c;但机会藏在不确定性中。 每一个弯道里&#xff0c;都有你超车的机会 意外、周期、趋势、规划 可是&#xff0c;为什么趋势一定是不可逆转的呢&#xff1f;因为&#xff0c;效率提高了 长期…...

用Excel辅助做数独

做数独游戏的时候&#xff0c;画在纸上很容易弄花眼&#xff0c;所以我考虑用Excel辅助做一个。 界面如下&#xff1a; 按下初始化表格区域按钮&#xff0c;会在所有单元格中填充“123456789”。如下图&#xff1a; 当某个单元格删除得只剩一个数字时&#xff0c;会将同一行、…...

arcgis实现截图/截屏功能

arcgis实现截图/截屏功能 文章目录 arcgis实现截图/截屏功能前言效果展示相关代码 前言 本篇将使用arcgis实现截图/截屏功能&#xff0c;类似于qq截图 效果展示 相关代码 <!DOCTYPE html> <html> <head><meta charset"utf-8"><meta nam…...

mysql备份

1.新建备份目录 mkdir -p /data/mysql_dump/#查找mysql配置位置 find / -name "my.cnf" find / -name "mysql.sock" find / -name "mysqldump"2.定时任务 #每天凌晨备份一次 echo "00 00 * * * root /data/mysql_bak.sh" >> /…...

CentOS7 安装PostgreSQL以及配置服务

文章目录 前言1. 安装步骤2. 连接PostgreSQL3. 配置服务配置文件所在路径设置监听地址修改数据库密码已经修改了密码,为什么没有生效?不需要密码就可以连接?设置访问权限4. 新的配置生效前言 PostgreSQL是一种功能强大的开源关系型数据库管理系统,被广泛用于各种应用程序和…...

React 表单、处理受控表单组件、非受控组件

React 表单处理 学习目标&#xff1a; 能够使用受控组件的方式获取文本框 使用 React 处理表单一般有两种方法 受控组件 &#xff08;推荐&#xff09;非受控组件 &#xff08;了解&#xff09; 1. 受控表单组件 什么是受控组件&#xff1f; input 框自己的状态被 React 组…...

Android开发--状态栏布局隐藏的方法

1.问题如下&#xff0c;安卓布局很不协调 2.先将ActionBar设置为NoActionBar 先打开styles.xml 3.使用工具类 package com.afison.newfault.utils;import android.annotation.TargetApi; import android.app.Activity; import android.content.Context; import android.graph…...

GaussDB如何创建和管理序列、定时任务

前言 GaussDB是华为自主创新研发的分布式关系型数据库&#xff0c;为企业提供功能全面、稳定可靠、扩展性强、性能优越的企业级数据库服务。在实际业务场景使用中&#xff0c;为了提高工作效率&#xff0c;数据库GaussDB提供定时任务的功能&#xff0c;本节为大家讲解GaussDB如…...

mybatis-plus:代码生成器

一、依赖 代码生成器需要添加一下依赖 <dependencies><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.0.7.1</version></dependency><!-- https://mvnre…...

几款提高开发效率的Idea 插件

1、ignore 开发代码过程中经常会有一些需要提交到代码仓库的文件&#xff0c;比如java文件生成的.class、.jar 等&#xff0c;如果将编译后的文件都提交到代码库那么代码库会很大&#xff0c;关键是没有必要。 这款插件就可以很方便的解决某类文件或者某个文件夹不需要提交到…...

Redisson 分布式锁可重入的原理

目录 1. 使用 Redis 实现分布式锁存在的问题 2. Redisson 的分布式锁解决不可重入问题的原理 1. 使用 Redis 实现分布式锁存在的问题 不可重入&#xff1a;同一个线程无法两次 / 多次获取锁举例 method1 执行需要获取锁method2 执行也需要&#xff08;同一把&#xff09;锁如…...

【Vue实用功能】Vue实现文档在线预览功能,在线预览PDF、Word等office文件

1、Office Web(微软的开发接口) 优点 没有 Office也可以直接查看Office 文件适用于移动端、PC无需下载文件就可以在浏览器中查看 <iframe src"文档地址" frameborder"0" /> const docUrl 外网可预览的地址 const url encodeURIComponent(docUrl…...

【一站解决您的问题】mac 利用命令升级nodejs、npm、安装Nodejs的多版本管理器n、nodejs下载地址

一&#xff1a;下载nodejs 官网地址&#xff0c;点击下载稳定版 https://nodejs.org/en 如果官网下载特别慢&#xff0c;可以点击这个地址下载 点击这里 https://nodejs.cn/download/current/ 安装完成后&#xff0c;就包含了nodejs 和 npm。此时您的版本就是下载安装的版本…...

【RabbitMQ】死信(延迟队列)的使用

目录 一、介绍 1、什么是死信队列(延迟队列) 2、应用场景 3、死信队列(延迟队列)的使用 4、死信消息来源 二、案例实践 1、案例一 2、案例二&#xff08;消息接收确认 &#xff09; 3、总结 一、介绍 1、什么是死信队列(延迟队列) 死信&#xff0c;在官网中对应的单词…...

java 解析word模板(2024-01-25)

本文主要功能是解析word模板 这是一个word解析类&#xff0c;因为我做的系统用到了而且没有可用的帮助类&#xff0c;只能自己写。之前的实现方式是freemarker 模板解析。但是这次要求用poi不在使用freemarker。实现功能比较少&#xff0c;主要是满足开发需求即可&#xff0c;没…...

flutter-相关个人记录

1、flutter 安卓打包打包报错 flutter build apk -v --no-tree-shake-icons 2、获取华为指纹证书命令 keytool -list -v -keystore ***.jks 3、IOS项目中私有方法查找隐藏文件中 1、cd 项目目录地址 2、grep -r xerbla. "xerbla"为需要查找的关键字 3…...

互斥锁/读写锁(Linux)

一、互斥锁 临界资源概念&#xff1a; 不能同时访问的资源&#xff0c;比如写文件&#xff0c;只能由一个线程写&#xff0c;同时写会写乱。 比如外设打印机&#xff0c;打印的时候只能由一个程序使用。 外设基本上都是不能共享的资源。 生活中比如卫生间&#xff0c;同一…...

Jackson序列化Bean额外属性附加--@JsonAnyGetter、@JsonUnwrapped用户

1. 场景 有一项工作&#xff0c;需要将数据从一个服务S中读取出来&#xff08;得到的是一个JSON&#xff09;&#xff0c;将数据解析转换以后构造成一个数组的类型A的对象&#xff0c;写入到一个服务T中。 A.class Data public class A {String f0 ;String f1 ; }在发现需要…...

排序算法——冒泡排序算法详解

冒泡排序算法详解 1.引言2.算法概览2.1输入处理2.2核心算法步骤2.3数据结构2.4复杂度分析 3.算法优化4.边界条件和异常处理5.实验和测试6.应用和扩展7.代码示例8.总结 1.引言 冒泡排序是一种简单而直观的比较排序算法&#xff0c;它通过多次遍历数组&#xff0c;比较相邻元素并…...

宋仕强论道之华强北的缺货潮(十六)

始于2019年缺货潮让华强北又生产一大批亿万富翁&#xff0c;缺货的原因主要是&#xff1a;首先&#xff0c;疫情封控导致大量白领在家远程办公&#xff0c;需要购买电脑、打印机等办公设备&#xff0c;同时孩子们也要在家上网课&#xff0c;进一步增加对电子智能终端产品的需求…...

登录注册页面

前提&#xff1a;基于element-ui环境 模态登录组件 分析Login.vue <template><div class"login"><span click"handleClose">X</span></div> </template><script> export default {name: "Login",m…...

wordpress的文章调用/网络推广要求

sudo apt install fbterm fbterm-ucimf ucimf-sunpinyin fbterm -i fbterm_ucimf之后可以在终端里输入和显示中文&#xff0c;效果还不错&#xff0c;嘿嘿&#xff5e;...

云空间的网站/发帖子最好的几个网站

先看一下真实的response是什么样的。 点击Inspectors->Raw&#xff0c;如果有乱码&#xff0c;有一行提示“Response is encoded and may require decoding before inspection. Click here to transform”&#xff0c;点一下就解析出来了。 点击View in Notepad&#xff0c;…...

wordpress 形式修改/南宁网站推广大全

模板介绍 本套商务工作汇报PPT模板,模板编号&#xff1a;P68475&#xff0c;大小10MB,共27页,比例为16:9,由封面、目录、转场页、内容、结尾5个部分构成。 内含青色,灰色,绿色多种配色&#xff0c;精美简约风格设计&#xff0c;动态播放效果&#xff0c;精美实用。 一份设计精…...

建站模板 discuz/成品网站源码的优化技巧

vs code 中eslint语法检测&#xff0c;保存即可格式化 具体查看&#xff1a;&#xff08;https://www.jianshu.com/p/23a5d6194a4b&#xff09; {// vscode默认启用了根据文件类型自动设置tabsize的选项"editor.detectIndentation": false,// 重新设定tabsize"e…...

北京品牌网站建设公司/网页设计模板

记录SQL server中datetime2(7)类型数据取年月日时分秒 –取值时间格式为&#xff1a;2021-08-19 Select CONVERT (CHAR(10), History.Date, 120) from History–其中Date为History表中的datetime2(7)类型的字段 –取值时间格式为&#xff1a;08:44:53 Select CONVERT (CHAR(10)…...

永久域名注册网站/aso苹果关键词优化

目录 背景 安装sequelize 定义配置文件 创建一个sequelize对象实例...