通俗理解Kotlin及其30大特性

news/发布时间2024/5/15 2:55:18

kotlin

通俗理解Kotlin及其30大特性

文章目录

  • 通俗理解Kotlin及其30大特性
    • 前言
      • 背景
      • 编译&运行
      • 字节码对比
    • Java VS Kotlin
      • 变量/常量
        • 类型声明
        • 变量初始化
        • 空安全特性
      • 函数
        • 函数声明
        • 函数参数
        • 函数可变参数
        • 局部函数
        • 函数/属性/操作符的扩展
        • 函数/属性的引用
        • 操作符重载
        • Lambda 表达式
        • 数组/List/Map/元组
      • 控制表达式
        • if/when
        • for/while
        • try-catch
        • 位运算
        • 类的定义/构造/继承
        • 类的访问修饰符
        • 数据类
        • 类的别名
    • 协程
    • 总结
      • 在AOSP中部分使用
      • 优缺点比较

前言

Kotlin是Jetbrain公司发明的编程语言之一,指在替换java。恰好Google此前和SUN公司因为java闹得打官司,所以Jetbrain机智地将Kotlin推荐给了Google Android。目前来看Kotlin在Android应用开发中起到了不错的效果。

背景

Kotlin的特色,引用官网说明:

image-20240218113127156

编译&运行

本质上,kotlin语言经过kotlin编译器也是编译成java字节码,可以运行在JVM虚拟机上。

由于多了一道转化工序,所以一般来说,Kotlin的编译时间会更长一些,产生的编译文件也大一些。

在这里插入图片描述

字节码对比

可以使用Android Studio/IDEA的工具查看Kotlin的字节码:

  • 点击菜单栏 -> Tool -> Kotlin -> Show Kotlin Bytecode,查看生成的Java字节码

  • 还可以点击顶部的"Decompile"按钮查看翻译后的Java代码

java 源码:

package com.xxxx.java;public class SDK {public static int addSum(int a, int b) {System.out.println("run in java sdk!");return a+b;}
}

java 字节码:

// class version 65.0 (65)
// access flags 0x21
public class com/xxxx/java/SDK {// compiled from: SDK.java// access flags 0x1public <init>()VL0LINENUMBER 3 L0ALOAD 0INVOKESPECIAL java/lang/Object.<init> ()VRETURNL1LOCALVARIABLE this Lcom/xxxx/java/SDK; L0 L1 0MAXSTACK = 1MAXLOCALS = 1// access flags 0x9public static addSum(II)IL0LINENUMBER 5 L0GETSTATIC java/lang/System.out : Ljava/io/PrintStream;LDC "run in java sdk!"INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)VL1LINENUMBER 6 L1ILOAD 0ILOAD 1IADDIRETURNL2LOCALVARIABLE a I L0 L2 0LOCALVARIABLE b I L0 L2 1MAXSTACK = 2MAXLOCALS = 2
}

kotlin 源码:

package com.xxxx.kotlinclass SDK {}fun addSum(a:Int, b:Int):Int {println("run in kotlin sdk!")return a+b;
}

kotlin字节码:

// ================com/xxxx/kotlin/SDK.class =================
// class version 52.0 (52)
// access flags 0x31
public final class com/xxxx/kotlin/SDK {// compiled from: SDK.kt@Lkotlin/Metadata;(mv={1, 9, 0}, k=1, d1={"\u0000\u000c\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\u0008\u0002\u0018\u00002\u00020\u0001B\u0005\u00a2\u0006\u0002\u0010\u0002\u00a8\u0006\u0003"}, d2={"Lcom/xxxx/kotlin/SDK;", "", "()V", "KotlinStudy"})// access flags 0x1public <init>()VL0LINENUMBER 3 L0ALOAD 0INVOKESPECIAL java/lang/Object.<init> ()VRETURNL1LOCALVARIABLE this Lcom/xxxx/kotlin/SDK; L0 L1 0MAXSTACK = 1MAXLOCALS = 1
}// ================com/xxxx/kotlin/SDKKt.class =================
// class version 52.0 (52)
// access flags 0x31
public final class com/xxxx/kotlin/SDKKt {// compiled from: SDK.kt@Lkotlin/Metadata;(mv={1, 9, 0}, k=2, d1={"\u0000\n\n\u0000\n\u0002\u0010\u0008\n\u0002\u0008\u0003\u001a\u0016\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u00012\u0006\u0010\u0003\u001a\u00020\u0001\u00a8\u0006\u0004"}, d2={"addSum", "", "a", "b", "KotlinStudy"})// access flags 0x19public final static addSum(II)IL0LINENUMBER 8 L0LDC "run in kotlin sdk!"ASTORE 2GETSTATIC java/lang/System.out : Ljava/io/PrintStream;ALOAD 2INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)VL1LINENUMBER 9 L1ILOAD 0ILOAD 1IADDIRETURNL2LOCALVARIABLE a I L0 L2 0LOCALVARIABLE b I L0 L2 1MAXSTACK = 2MAXLOCALS = 3
}

【java字节码 vs kotlin字节码】

image-20240220170229919

核心函数的字节码不变,在形式上稍微有调整。

Java VS Kotlin

变量/常量

类型声明

Java:

  • 使用关键字 intString 等来声明变量类型,例如 int num = 10;
    private static void test1() {int num=10;System.out.println("what's type of num?"+getType(num));String str="Hello, world!";System.out.println("what's type of str?"+getType(str));final int N=10;//N=11;System.out.println("N="+N);}

Kotlin:

  • 使用关键字 varval 来声明变量,例如 var num: Int = 10val name: String = "Kotlin"

  • 默认支持局部变量类型推断,使用关键字 valvar 声明变量

  • var是可变变量,val一旦赋值不可再变,相当于javafinal

fun test1(){var num = 10println("what's type of num?${num::class.java.typeName}")var str = "Hello, world!"println("what's type of str?" + getType(str))val N = 10//N = 11println("N=$N")//const val PI = 3.14println(PI)val a: Int = 10val b: Long = a.toLong()println("what's type of b? $b-->" + getType(b))
}

Kotlin使用关键字 const(只能用于顶层和对象声明)和 val(只读变量)来声明常量,

const 只能修饰属性(类属性、顶层属性),不能用于局部变量,再编译期间定下来,所以它的类型只能是 String 或基本类型。

例如:

const val PI = 3.14
val name: String = "Kotlin"

Kotlin数据类型转换方式更为简洁,例如:

val a: Int = 10
val b: Long = a.toLong()
变量初始化

lateinit 是一种延迟初始化方式,必须在使用前初始化,例如:

lateinit var name: String
fun init() {name = "Kotlin"
}

lazy 是一种懒加载方式,会在第一次访问时初始化,例如:

val name: String by lazy {println("Initializing")"Kotlin"
}

lateinit varby lazy都可以推迟初始化。

lateinit var只是在编译期忽略对属性未初始化进行检查,何时初始化还需开发者自行决定。

by lazy在被第一次调用的时候能自动初始化,做到了真正的延迟初始化的行为。

空安全特性

Java:不支持空安全特性,需要手动判断 null 值。

private static void test2() {String str=null;System.out.println(str);if ( str != null) {System.out.println(str.substring(0,1));}
}

Kotlin:支持空安全特性,使用 ? 来标记可为空的类型,例如 var name: String? = null

var str: String? =null;
println(str)
println(str?.substring(0,1))
println(str?.length) // 如果 str 不为 null,返回 str 的长度,否则返回 null

此外,Kotlin还支持非空断言,使用 !! 运算符,相当于回归java设计,例如:

println(str!!.length) // 如果 str 不为 null,返回 str 的长度,否则抛出 NullPointerException

运行时会报错:

Exception in thread "main" java.lang.NullPointerExceptionat com.xxxx.kotlin.KotlinMainTestKt.test2(KotlinMainTest.kt:163)at com.xxxx.kotlin.KotlinMainTestKt.main(KotlinMainTest.kt:16)

Elvis 运算符是一种处理空值的方式,可以指定一个默认值,例如

val str: String? = null
val length = str?.length ?: 0 // 如果 str 不为 null,返回 str 的长度,否则返回 0

Kotlin:安全类型转换是一种转换类型的方式,可以避免类型转换异常,例如:

val str: Any = "Kotlin"
val length = (str as? String)?.length ?: 0

函数

函数声明

Java:使用关键字 void 来声明函数的返回类型,例如 public void printName(String name) {}

    private static String test3() {return "String";}

Kotlin:使用关键字 fun 来声明函数,例如 fun printName(name: String) {}

private fun test3(): String {return "String"
}

此外,

  • Kotlin调用静态方法,无需带上包名,可以直接调用,这一点体现了kotlin的静态性。
  • Kotlin函数调用,也无须分号结尾。
函数参数

Java:不支持函数的默认参数。

    private static void test4(String name, Boolean isMale) {System.out.println("name="+name+", isMale="+isMale);}

Kotlin:支持函数的默认参数,例如 fun printName(name: String, isMale: Boolean = true) {}

test4("haha")fun test4(name: String, isMale: Boolean = true) {println("name=$name, isMale=$isMale")
}

此外,类的构造函数也支持默认参数:

class Person(val name: String = "Kotlin", val age: Int = 20)

Kotlin:具名参数是一种通过名称来指定函数参数的方式,可以提高代码可读性,例如:

fun printPerson(name: String, age: Int) {println("Name: $name, Age: $age")
}
printPerson(name = "Kotlin", age = 20)
fun main(){test4("kotlin",false)test4("haha")                         //默认参数test4( isMale = false, name="Lucas")  //具名参数
}fun test4(name: String, isMale: Boolean = true) {println("name=$name, isMale=$isMale")
}
函数可变参数

Java:使用 ... 来声明可变参数,例如 public void printNames(String... names) {}

    private static void test5(String... names) {for (int i = 0; i < names.length; i++) {System.out.println(names[i]);}}

Kotlin:使用关键字 vararg 来声明可变参数,例如 fun printNames(vararg names: String) {}

fun test5(vararg names: String) {for ( name in names){println(name)}
}
局部函数

函数中仍然可以嵌套函数,对于函数内代码块频繁调用的情况有用。

fun test6() {fun sum(a:Int, b:Int): Int {fun multiply(c:Int, d:Int): Int{return c*d}return multiply(a, a)+multiply(b, b);}// 平方和println(sum(1,2))
}
函数/属性/操作符的扩展
  • 扩展函数是一种将函数添加到现有类中的方式
  • 扩展属性是一种将属性添加到现有类中的方式
val String.lastChar: Charget() = get(length - 1)
val String.pai: Stringget() = "3.1415926"
val String.isEmail: Booleanget() = this.matches(Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"))fun test7() {fun String.addHello() = this + ", Hello!"println("Lucas".addHello());println("Lucas".lastChar);println(String().pai);println("lucas.deng@xxxx.com".isEmail);
}
  • 扩展运算符是一种将数组或集合打散为参数列表的方式,例如:
fun sum(a: Int, b: Int, c: Int) = a + b + c
val list = listOf(1, 2, 3)
val result = sum(*list.toIntArray())
函数/属性的引用
  • 支持属性引用,可以使用 :: 运算符来引用属性

  • 支持函数引用,可以使用 :: 运算符来引用函数

fun test8() {class Person(val name: String) {fun printName() {println(name)}}val person = Person("Kotlin")val nameProperty = Person::nameprintln(getType(nameProperty))println(nameProperty.toString())val name = nameProperty.get(person)println(name)fun printName(name: String) {println(name)}val namePrinter = ::printNamenamePrinter("Kotlin")val c= String::classprintln(c)val d= String::toStringprintln(d("abc"))val e= String::equalsprintln(e("abc", "abc"))}
操作符重载

不是所有操作符都支持重载,支持的操作符主要是运算类的。

表达式翻译为
a + ba.plus(b)
a - ba.minus(b)
a * ba.times(b)
a / ba.div(b)
a % ba.rem(b)
a..ba.rangeTo(b)
a..<ba.rangeUntil(b)
fun test9() {data class Point(val x: Int, val y: Int) {operator fun plus(other: Point) = Point(x + other.x, y + other.y)operator fun minus(other: Point) = Point(x - other.x, y)}val p1 = Point(1, 2)val p2 = Point(3, 4)val p3 = p1 + p2println(p3)val p4 = p2 - p1println(p4)}
Lambda 表达式

Java:支持 Lambda 表达式,但写法比较繁琐。

如果只有一个显式声明的抽象方法,那么它就是一个函数接口。

java Lambda表达式只能应用于函数接口。

    private static void test12(){new Thread(() -> System.out.println("Thread run().....")).start();Call call= (a,b)->{ return a+b; };System.out.println(call.plus(1,4));}static interface Call {int plus(int a, int b);// int minus(int a, int b);}

Kotlin:支持 Lambda 表达式,写法简洁,例如 val sum = { a: Int, b: Int -> a + b }

private fun test10() {Thread { println("Thread run().....") }.start()val sum = { a: Int, b: Int -> a + b }println(sum(1,4))
}

Java:使用 for 循环和 if 语句来实现过滤器。

Kotlin:使用 Lambda 表达式和过滤器函数来实现,例如 val nums = listOf(1, 2, 3, 4, 5).filter { it % 2 == 0 }

private fun test10() {Thread { println("Thread run().....") }.start()val sum = { a: Int, b: Int -> a + b }println(sum(1,4))val nums = listOf(1, 2, 3, 4, 5).filter { it % 2 == 0 }println(nums)
}
数组/List/Map/元组

数组: 不再使用[ ], 而是用Array类来代替掉,

List: 直接用listOf就可以进行初始化,直接用forEach就可以打印所有元素

Map: 直接用hashMapOf就可以进行初始化,直接用forEach就可以打印所有元素

元组:支持元组,使用 PairTriple 类来表示二元组和三元组。主要用于记录小量的二元/三元数据,而不必要重新定义一个类。

fun test11() {//数组val arrayEmpty = emptyArray<String>()val array1 = arrayOfNulls<Int>(5)val array2 = arrayOf(1, 2, 3, 4)array2.forEach {print(" $it")}println()// Listval listEmpty = emptyList<String>()val nums = listOf(1, 2, 3, 4, 5)val sum = nums.reduce { acc, i -> acc + i }for (item in nums)print(" $item")println()val map = hashMapOf("Kotlin" to 1, "Java" to 2, "Python" to 3)println(map["Kotlin"])map["Lucas"] = 23println(map["Lucas"])for ((key, value) in map) {print("$key = $value, ")}println()map.forEach {(key, value) -> print("$key = $value, ")}println()val pair = Pair("Kotlin", 20)val triple = Triple("Kotlin", 20, "male")val (name, age) = pairprintln(pair)println(triple)val triple2 = Triple("Lucas", 27, "male")var arrays = arrayOf(triple,triple2)arrays.forEach {println(it)}
}

控制表达式

if/when

Java:

使用 if-else if-else 或 switch-case 来实现条件判断。

Kotlin:

if 表达式是有返回值的,可以用来赋值,基本可以代替三目运算符,例如:

fun test12() {val a = 10val b = 20//val max = a>b? a:bval max = if (a > b) a else bprintln(max)val value = 88if (value in 1..100) {println("$value")}}

使用 when 表达式,例如:

fun test14( index : String): String {val num=10;when(index){"a"->return "A""b"->return "B""c"->return "C"}return when(num){1-> "99"2-> "88"3-> "77"else->"-1"}
}fun test13() {var num=34when(num){10 -> println("10")23 -> println("23")34 -> println("OK!")35 -> println("35")}
}

不再需要break,不然又有什么坑要踩。

for/while

Kotlin:for 循环可以遍历集合、数组等对象,例如:

val list = listOf("Kotlin", "Java", "Python")
for (item in list) {println(item)
}

Kotlin:支持 Range 表达式,例如 val nums = 1..10

fun test15() {for (i in 1..9) {print(i)}println()for (i in 9..1) {print(i)}println()for (i in 9 downTo 1) {print(i)}println()for (i in 1..20 step 2) {print(i)}println()for (i in 1 until 10) {print(i)}println()
}

Kotlin:while 循环可以重复执行某个代码块,例如:

var i = 0
while (i < 10) {println(i)i++
}

Kotlin:do-while 循环与 while 循环类似,但是至少会执行一次,例如:

var i = 0
do {println(i)i++
} while (i < 10)
fun test16() {var i = 0while (i < 10) {print(i)i++}println()var j = 0do {print(j)j++} while (j < 10)println()}
try-catch

Java:使用 try-catch 语句块来捕获异常。

Kotlin:不仅可以使用语句块,还能使用 try-catch 表达式来捕获异常,例如:

fun test17() {try {val str:String? = null;println(str!!.length)}catch (e:NullPointerException){println("please check your code!")}val len = try {val str:String? = null;println(str!!.length)}catch (e:NullPointerException){println("please check your code!")5}println(len)
}
位运算

Kotlin:位运算是一种对二进制位进行操作的方式,例如:

fun test18() {val a = 0b0101val b = 0b1010val c = a and b // 0b0000val d = a or b // 0b1111val e = a xor b // 0b1111val f = a.inv() // 0b1010println(c)println(d)println(e)println(f)println(Integer.toBinaryString(e))println(Integer.toBinaryString(f))}

类的定义/构造/继承

最简单的类定义:

class Emptyclass Anything{
}

定义Person类,并调用

open class Person //主构造Person()
{constructor(id: Int, name: String) {}constructor(id: Int, sex: Char) {}//主构造constructor() {}override fun toString(): String {return "abc"}}
fun test19() {var person:Person = Person()var person2:Person = Person(110,'C')var person3:Person = Person(10086, "Lucas")
}

Java:使用关键字 extends 来实现类的继承,例如 public class Student extends Person {}

    private static void test7() {Student student = new Student();System.out.println(student);}static class Student extends Person {}static class Person {String name = "David";int age = 23;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}}

Kotlin:使用关键字 : 来实现类的继承,例如 class Student : Person()

并且Person必须为open,定义Student类,继承至Person

class Student() : Person()
{// Kotlin 全部都是没有默认值的// Java 成员有默认值,但是方法内部没有默认值// lateinit 懒加载  没有赋值 就不能使用,否则报错lateinit var name : Stringvar age: Int = 0override fun toString(): String {return "Student(name='$name', age=$age)"}constructor(n:String) : this() {name = n}constructor(n:String, a:Int) : this() {name = nage = a}}
fun test20() {var student:Student = Student("Hello")println(student.toString())
}

实现接口:

interface Eat {fun EatMethod() : Boolean
}
class Student() : Person(), Eat
{override fun EatMethod(): Boolean {TODO("Not yet implemented")}...
}
类的访问修饰符

Java:使用关键字 publicprivateprotecteddefault(没有修饰符)来修饰类的访问权限。

image-20240218154616640

Kotlin:使用关键字 publicprivateprotectedinternal 来修饰类的访问权限,默认为 public

image-20240218154726169

数据类

Java:不支持数据类。

	private static void test10() {User jack = new User("Jack", 23);System.out.println(jack.toString());}static class User{String username;int age;public User(String username, int age) {this.username = username;this.age = age;}}

Kotlin:

支持数据类,使用关键字 data 来声明,例如 data class User(val id: Int, val name: String, val sex: Char)

编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:

  • equals() / hashCode()
  • toString() 格式如 "User(name=John, age=42)"
  • componentN() functions 对应于属性,按声明顺序排列
  • copy() 函数
fun test21() {val user = User(99, "Lucas", 'M')val(myID, myName, mySex) = user.copy()println("myID:$myID, myName:$myName, mySex:$mySex")// _ 代表不接收val(_, myName2, _) = user.copy()println("myName2:$myName2")println(user.toString())val user1=user.copy()val user2=user.copy(name="Kotlin")println(user1.equals(user))println(user2.equals(user))}
类的别名

Java:不支持类型别名。

Kotlin:支持类型别名,使用关键字 typealias 来声明,例如:

typealias Name = String
typealias MyList = List<String>
fun test22() {fun printName(name: Name) {}val list: MyList = listOf("Kotlin", "Java", "Python")
}

此外,内部类和枚举类也和java稍有不同,可以自行查阅。

协程

Kotlin中的协程可以认为是一个“线程框架”,类似于Java中的线程池Executor,类似于Android中的Handler/AsyncTask。

Kotlin 协程的最大好处在于,你可以把运行的不同线程的代码写在同一个代码块里,可以随意切。(用看起来同步的方式写出异步代码)

总结

在AOSP中部分使用

以frameworks/base/packages/SystemUI为例,kt文件有510个java文件有1220个占比达到了1/3。

find  ./frameworks/base/packages/SystemUI/src  -name "*.kt" |  wc -l
510
find  ./frameworks/base/packages/SystemUI/src  -name "*.java" |  wc -l
1220

优缺点比较

JavaKotlin
优点改进错误检测和解决的检查异常
提供详细的文档。
大量熟练的开发人员可用
大量的第 3 方库
它允许您形成标准程序和可重用代码。
它是一个多线程环境,允许您在一个程序中同时执行多个任务。
完美的表现
易于浏览的社区资料
使用 Kotlin 多平台框架,您可以提取一个通用代码库,同时针对所有这些代码库
Kotlin 提供了内置的 null 安全支持,这是一个救星,尤其是在 Android 上,它充满了旧的 Java 风格的 API。
它比 Java 更简洁、更具表现力,这意味着出错的空间更小。
提供用户友好且易于理解的编码规范
将大型应用程序划分为更小的层。
使用大量函数类型和专门的语言结构,如 lambda 表达式。
帮助开发者创建扩展功能
提供了一种非常简单且几乎自动化的方式来创建数据类
Kotlin 是一种静态类型语言,因此非常易于阅读和编写。
这种语言允许以各种方式交换和使用来自 Java 的信息。
在 Kotlin 中编写新代码将花费更少的时间。
部署 kotlin 代码并大规模维护它非常容易。
缺点由于诸多限制,不太适合 Android API 设计
需要大量手动工作,这增加了潜在错误的数量
JIT 编译器使程序相对较慢。
Java 具有较高的内存和处理要求。
它不支持像指针这样的低级编程结构。
您无法控制垃圾收集,因为 Java 不提供 delete()、free() 等函数。
开发者社区很小,因此缺乏学习材料和专业帮助。
Java 不提供可能导致错误的检查异常的功能。
编译速度比Java慢
编译的产物比java大
Kotlin 作为一种高度声明性的语言,有时它可以帮助您在相应的 JVM 字节码中生成大量样板

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

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

相关文章

chatGPT PLUS 绑卡提示信用卡被拒的解决办法

chatGPT PLUS 绑卡提示信用卡被拒的解决办法 一、 ChatGPT Plus介绍 作为人工智能领域的一项重要革新&#xff0c;ChatGPT Plus的上线引起了众多用户的关注&#xff0c;其背后的OpenAI表现出傲娇的态度&#xff0c;被誉为下一个GTP 4.0。总的来说&#xff0c;ChatGPT Plus的火…

[SUCTF 2019]EasySQL1 题目分析与详解

一、题目介绍 1、题目来源&#xff1a; BUUCTF网站&#xff0c;网址&#xff1a;https://buuoj.cn/challenges 2、题目描述&#xff1a; 通过以上信息&#xff0c;拿到flag。 二、解题思路 首先打开靶机&#xff0c;尝试输入1查看回显&#xff0c;回显如图所示&#xff1a;…

Android studio 六大基本布局详解

Android studio 六大基本布局详解 一、Android studio1.Android studio简介2.架构组成3.地址3.1 [官网地址](https://developer.android.google.cn/)3.2 [官方下载地址](https://developer.android.google.cn/studio?hlzh-cn) 二、Android studio六大基本布局详解1.Android六大…

MySQL加锁策略详解

我们主要从三个方面来讨论这个问题&#xff1a; 啥时候加&#xff1f;如何加&#xff1f;什么时候该加什么时候不该加&#xff1f; 1、啥时候加 1.1 显式锁 MySQL 的加锁可以分为显式加锁和隐式加锁&#xff0c;显式加锁我们比较好识别的&#xff0c;因为他往往直接体现在 S…

【Java程序设计】【C00287】基于Springboot的疫情防控期间某村外出务工人员管理系统(有论文)

基于Springboot的疫情防控期间某村外出务工人员管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的疫情防控期间某村外出务工人员信息管理系统 本系统分为系统功能模块、管理员功能模块、用户功能模块、采集…

el-table实现嵌套表格的展示

需求 一个表单中存在子表 列表返回格式 实现 实现思路 el-table中在嵌套一个el-table&#xff0c;这样数据格式就没问题了&#xff0c;主要就是样式 将共同的列放到一列中&#xff0c;通过渲染自定义表头render-header&#xff0c;将表头按照合适的宽度渲染出来 <el-…

React 模态框的设计(二)

自定义组件是每个前端开发者必备的技能。我们在使用现有框架时难免有一些超乎框架以处的特别的需求&#xff0c;比如关于弹窗&#xff0c;每个应用都会用到&#xff0c;但是有时我们使用的框架中提供的弹窗功能也是功能有限&#xff0c;无法满足我们的应用需求&#xff0c;今天…

【Python】实现一个类似于Glass2k的Windows窗口透明化软件

一 背景说明 网上看到一款Windows下的窗口透明化工具Glass2k&#xff08;Glass2k官网&#xff09;&#xff0c;可以简单地通过快捷键实现任意窗口的透明化&#xff0c;还挺方便的&#xff0c;想用Python自己实现一下类似的功能。 软件已经开源到&#xff1a;窗口透明化小工具开…

网络原理TCP之“三次握手“

TCP内核中的建立连接 众所周知,TCP是有连接的. 当我们在客户端敲出socket new Socket(serverIp,severPort)时,就在系统内核就在建立连接 真正建立连接是在系统内核中建立的,我们程序员只是调用相关的api. 在此处,我们把TCP的建立连接称为三次握手. 系统在内核建立连接时如上…

【Java程序员面试专栏 数据结构】四 高频面试算法题:哈希表

一轮的算法训练完成后,对相关的题目有了一个初步理解了,接下来进行专题训练,以下这些题目就是汇总的高频题目,一个O(1)查找的利器哈希表,所以放到一篇Blog中集中练习 题目关键字解题思路时间空间两数之和辅助哈希使用map存储出现过的值,key为值大小,value为下标位置,…

Ansible 常见模块

模块文档 官方模块列表&#xff1a;https://docs.ansible.com/ansible/latest/collections/index_module.html # 查看支持的模块&#xff08;小写 l&#xff09; ansible-doc -l # 查看支持的模块个数-> 3387 ansible-doc -l | wc -l # ansible-doc 模块名 或者 ansible-…

笔记本hp6930p安装Android-x86避坑日记

一、序言 农历癸卯年前大扫除&#xff0c;翻出老机hp6930p&#xff0c;闲来无事&#xff0c;便安装Android-x86玩玩&#xff0c;期间多次入坑&#xff0c;随手记之以避坑。 笔记本配置&#xff1a;T9600,4G内存&#xff0c;120G固态160G机械硬盘 二、Android-x86系统简介 官…

深入理解网络通信和TCP/IP协议

深入理解网络通信和TCP/IP协议 OSI 七层模型 与 TCP/IP 五层模型 OSI 七层模型 应用层、表示层、会话层: 为程序提供服务&#xff0c;处理数据以及会话管理&#xff0c;比如MySQL 传输层&#xff1a;处理端与端的连接&#xff0c;比如TCP 网络层: IP地址以及路由选择 数据链…

Matlab/simulink基于MPPT风光储微电网建模仿真(持续更新)

​ 2.Matlab/simulink基于MPPT风光储微电网建模仿真&#xff08;持续更新&#xff09; 1.Matlab/simulink基于vsg的风光储调频系统建模仿真&#xff08;持续更新&#xff09;

企微hook框架

https://wwm.lanzoum.com/ipUTp1ot1twh 密码:hvev 免费的企微框架 支持文本消息&#xff0c;图片消息&#xff0c;视频消息&#xff0c;文件消息。 其他可自行下载测试。 有兴趣可以进群交流。720192224 BOOL WxWorkSendData(string data) { WX_GETOBJDATA ob…

隐藏饿了么el-select组件的el-select-dropdown部分,只使用el-select的显示框

隐藏饿了么el-select组件的el-select-dropdown部分,只使用el-select的显示框 问题: 由于el-select组件的el-select-dropdown部分是自动插入在最外层Body上的&#xff0c;所以在当前组件的scoped中让el-select-dropdown组件display:none不会生效所以需要&#xff1a; :popper-…

数据结构 计算结构体大小

一、规则&#xff1a; 操作系统制定对齐量&#xff1a; 64位操作系统&#xff0c;默认8Byte对齐 32位操作系统&#xff0c;默认4Byte对齐 结构体对齐规则&#xff1a; 1.结构体整体的大小&#xff0c;需要是最大成员对齐量的整数倍 2.结构体中每一个成员的偏移量需要存在…

小果金融数据库程序---支持第三方库,提供程序

我这几天把程序打包了程序完全支持第三方库调用服务器数据&#xff0c;我简单的写了一些例子api&#xff0c;可以完全利用代码调用数据 点击数据界面的结果 随便点击一个数据 或到的数据 可以在文件夹下面的数据看到&#xff0c;自动下载 比如点击可转债热度 数据表自动下载 强…

Linux安装Zookeeper

目录 下载配置启动 下载 下载链接 https://archive.apache.org/dist/zookeeper/上传 我直接本地下好了&#xff0c;拖到对应文件夹解压&#xff0c;重命名&#xff0c;注意路径 tar -zxvf /opt/Zookeeper/apache-zookeeper-3.7.2-bin.tar.gz -C /opt/ mv /opt/apache-zookeep…

代码随想录算法训练营第59天 | 583.两个字符串的删除操作 + 72.编辑距离 + 编辑距离总结篇

今日任务 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇 583.两个字符串的删除操作 - Medium 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以…
推荐文章