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

Android 之 Kotlin

变量

变量的声明

Kotlin使用var,val来声明变量,注意:Kotlin不再需要;来结尾

var 可变变量,对应java非final变量

var b = 1

val不可变变量,对应javafinal变量

val a = 1

两种变量并未声明类型,这是因为Kotlin存在类型推导机制,上述的a,b默认为Int。假设想声明具体类型,则需下面的方式。

var c: Int = 1
基本类型

Kotlin不再存在基本类型,将全部使用对象类型

Java基本类型Kotlin对象类型对象类型说明
intInt整型
longLong长整型
shortShort短整型
floatFloat单精度浮点型
doubleDouble双精度浮点型
booleanBoolean布尔型
charChar字符型
byteByte字节型

函数

函数的声明

无参无返回值

fun test() {
}

有参有返回值

参数的类型需要写在形参名后面中间使用:连接多个参数使用,分割",“返回值使用”:"拼接

fun add(a: Int, b: Int): Int {return a + b
}

声明技巧

当函数体只有一行代码时可直接使用下面方式声明方法

fun add (a: Int, b: Int): Int = a + b 

Kotlin存在类型推导,返回值类型也可省略

fun add (a: Int, b: Int) = a + b
函数的调用
fun main() {test()println(add(1, 2))
}//运行结果
//test
//3

if语句

Kotlin中的选择控制有两种方式。ifwhen

if

Javaif区别不大,实现一个返回最大值的函数

fun max(a: Int, b: Int): Int {if (a > b) return aelse return b
}

Kotlin的if可以包含返回值,if语句的最后一行会作为返回值返回

fun max(a: Int, b: Int): Int {return if (a > b) a else b
}

上述我们说过一行代码可省略返回值

fun max(a: Int, b: Int) = if (a > b) a else b

when语句

实现一个查询成绩的函数,用户传入名字,返回成绩级别

if实现

Kotlinif语句必须要有else,不然会报错

fun getScore(name: String) = if (name == "Tom") "不及格"
else if (name == "Jim") "及格"
else if (name == "Pony") "良好"
else if (name == "Tony") "优秀"
else "名字非法"

Kotlin==等价于Javaequals比较的时是对象里的内容, === 等价于Java==,比较的为对象的引用。

when实现(相当于swich)

也必须实现else,否则报错

fun getScore(name: String) = when(name) {"Tom" -> "不及格""Jim" -> "及格""Pony" -> "良好""Tony" -> "优秀"else -> "名字非法"
}

循环语句

Kotlin有两种循环方式,whilefor-inwhilejava中的while没有区别,for-in是对Java for-each的加强,Kotlin舍弃了for-i的写法

while不再赘述,在学习for-in之前需要明确一个概念-区间

val range = 0..10 //区间代表[0,10]

for-in需借助区间来使用

fun main() {val range = 0..10for (i in range) { //也可直接for (i in 0..10)println(i)}//输出结果为 从0打印到10
}

0..10 代表双闭区间,如果想使用左闭右开呢,需要借助until关键字

fun main() {for (i in 0 until 10) {println(i)}//输出结果为 从0打印到9
}

上述实现是逐步进行相当于i++Kotlin支持跳步

fun main() {for (i in  0 until 10 step 2) {println(i)}//输出结果为0,2,4,6,8
}

for-in不仅可对区间进行遍历,还可对集合进行遍历,后续在集合处进行展示。

类和对象

类的创建和对象的初始化

创建Person类,并声明nameage,创建printInfo方法

class Person {var name = ""var age = 0fun printInfo() {println(name +"'s age is " + age)}
}

main方法中声明一个Person对象并调用printInfo方法

fun main() {val person = Person()person.name = "zjm"person.age = 20person.printInfo()
}
//结果如下zjm's age is 20
继承

声明Student类继承PersonKotlin中继承使用**:**,后接父类的构造,为什么需要构造后续讲解

class Student : Person(){ //此时Person报错var number = ""var grade = 0fun study() {println(name + "is studying")}
}

Person类为final不可被继承,因此需借助open关键字

只需在Person类前加上open

open class Person {...
}
构造

构造分为主构造和此构造

主构造

主构造直接写在类后面

修改Student

class Student(val number: String, val grade: Int) : Person(){...
}

因之前Person还有nameage,下面修改Person类的主构造

open class Person(val name: String, val age: Int) {...
}

此时Student报错,因为继承Person时,后边使用的是Person()无参构造,上面我们修改了Person的构造,则不存在无参构造了。

再修改Student

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){...
}

此时不在报错,声明方式如下

val student = Student("zjm", 20, "1234", 90)

在构造时需要进行特殊处理怎么办,Kotlin提供了init结构体,主构造的逻辑可在init中处理

open class Person(val name: String, val age: Int) {init {println("name is" + name)println("age is" + age)}
}

上述修改都为主构造,那如果类想有多个构造怎么办,此时需借助次构造

次构造

此时实现Student的另外两个构造

三个参数的构造,nameagenumbergrade不传参默认为``0

无参构造,字符串默认为"",int默认为0

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {}constructor() : this("", 0, "", 0) {}...
}

创建如下:

fun main() {val student1 = Student("zjm", 20, "123", 90)val student2 = Student("zjm", 20, "123")val student3 = Student()
}
无主构造

若类不使用主构造,则后续继承类也不需要使用构造即可去掉继承类的(),次构造可以调用父类构造super进行初始化,但是次构造的参数在其他地方无法引用

class Student : Person {constructor(name: String, age: Int, number: String) : super(name, age) {}fun study() {//name,age可使用println(name + "is studying")//使用number则会报错,若number是主构造的参数则可引用//println(number) 报红}
}

接口

接口的定义

Java中的接口定义类似

interface Study {fun study()fun readBooks()fun doHomework()
}
接口的继承

继承接口只需在后用","拼接,需实现Study声明的全部函数

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age), Study{...override fun study() {TODO("Not yet implemented")}override fun readBooks() {TODO("Not yet implemented")}override fun doHomework() {TODO("Not yet implemented")}
}

Kotlin支持接口方法的默认实现,JDK1.8以后也支持此功能,方法有默认实现则继承类无需必须实现此方法

interface Study {fun study() {println("study")}fun readBooks()fun doHomework()
}

权限修饰符

JavaKotlin的不同如下表所示:

修饰符JavaKotlin
public所有类可见所有类可见(默认)
private当前类可见当前类可见
protected当前类,子类,同包下类可见当前类,子类可见
default同包下类可见(默认)
internal同模块下的类可见

Kotlin引入internal,摒弃了default

使用:

类上

public open class Person(val name: String, val age: Int){...}

 变量上

private val value = 1

方法上

private fun test() {}

数据类和单例类

数据类

数据类则只处理数据相关,与Java Bean类似,通常需要实现其getsethashCodeequalstoString等方法

下面实现UserBean,包含idnamepwd属性

Java编写入如下:

public class UserBean {private String id;private String name;private String pwd;public UserBean() {}public UserBean(String id, String name, String pwd) {this.id = id;this.name = name;this.pwd = pwd;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;UserBean userBean = (UserBean) o;return Objects.equals(id, userBean.id) && Objects.equals(name, userBean.name) && Objects.equals(pwd, userBean.pwd);}@Overridepublic int hashCode() {return Objects.hash(id, name, pwd);}@Overridepublic String toString() {return "UserBean{" +"id='" + id + '\'' +", name='" + name + '\'' +", pwd='" + pwd + '\'' +'}';}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}
}

Kotlin编写此类将变得非常简单

一行代码即可搞定,Kotlin会自动实现上述方法。

data class UserBean(val id: String, val name: String, val pwd: String)

若无data关键字,上述方法hashCodeequalstoString无法正常运行,去掉data查看Kotlin对应的java文件:

public final class UserBean {@NotNullprivate final String id;@NotNullprivate final String name;@NotNullprivate final String pwd;@NotNullpublic final String getId() {return this.id;}@NotNullpublic final String getName() {return this.name;}@NotNullpublic final String getPwd() {return this.pwd;}public UserBean(@NotNull String id, @NotNull String name, @NotNull String pwd) {Intrinsics.checkNotNullParameter(id, "id");Intrinsics.checkNotNullParameter(name, "name");Intrinsics.checkNotNullParameter(pwd, "pwd");super();this.id = id;this.name = name;this.pwd = pwd;}
}

发现上面代码既无hashCodeequalstoString也无set

加上data且把变量改为var,对应的java文件如下:

public final class UserBean {@NotNullprivate String id;@NotNullprivate String name;@NotNullprivate String pwd;@NotNullpublic final String getId() {return this.id;}public final void setId(@NotNull String var1) {Intrinsics.checkNotNullParameter(var1, "<set-?>");this.id = var1;}@NotNullpublic final String getName() {return this.name;}public final void setName(@NotNull String var1) {Intrinsics.checkNotNullParameter(var1, "<set-?>");this.name = var1;}@NotNullpublic final String getPwd() {return this.pwd;}public final void setPwd(@NotNull String var1) {Intrinsics.checkNotNullParameter(var1, "<set-?>");this.pwd = var1;}public UserBean(@NotNull String id, @NotNull String name, @NotNull String pwd) {Intrinsics.checkNotNullParameter(id, "id");Intrinsics.checkNotNullParameter(name, "name");Intrinsics.checkNotNullParameter(pwd, "pwd");super();this.id = id;this.name = name;this.pwd = pwd;}@NotNullpublic final String component1() {return this.id;}@NotNullpublic final String component2() {return this.name;}@NotNullpublic final String component3() {return this.pwd;}@NotNullpublic final UserBean copy(@NotNull String id, @NotNull String name, @NotNull String pwd) {Intrinsics.checkNotNullParameter(id, "id");Intrinsics.checkNotNullParameter(name, "name");Intrinsics.checkNotNullParameter(pwd, "pwd");return new UserBean(id, name, pwd);}// $FF: synthetic methodpublic static UserBean copy$default(UserBean var0, String var1, String var2, String var3, int var4, Object var5) {if ((var4 & 1) != 0) {var1 = var0.id;}if ((var4 & 2) != 0) {var2 = var0.name;}if ((var4 & 4) != 0) {var3 = var0.pwd;}return var0.copy(var1, var2, var3);}@NotNullpublic String toString() {return "UserBean(id=" + this.id + ", name=" + this.name + ", pwd=" + this.pwd + ")";}public int hashCode() {String var10000 = this.id;int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;String var10001 = this.name;var1 = (var1 + (var10001 != null ? var10001.hashCode() : 0)) * 31;var10001 = this.pwd;return var1 + (var10001 != null ? var10001.hashCode() : 0);}public boolean equals(@Nullable Object var1) {if (this != var1) {if (var1 instanceof UserBean) {UserBean var2 = (UserBean)var1;if (Intrinsics.areEqual(this.id, var2.id) && Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.pwd, var2.pwd)) {return true;}}return false;} else {return true;}}
}

此时则和手动编写的java bean功能一样了,所有方法都可正常运行

单例类

目前Java使用最广的单例模式的实现如下:

public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}public void test() {...}
}

Kotlin中创建单例类需选择Object

生成代码如下

object Singleton {fun test() {...}
}

其对应的java文件如下,和上述使用最多的java单例实现类似

public final class Singleton {@NotNullpublic static final Singleton INSTANCE;public final void test() {}private Singleton() {}static {Singleton var0 = new Singleton();INSTANCE = var0;}
}

 使用如下:

fun main() {Singleton.test() //对应的java代码为Singleton.INSTANCE.test();
}

许多高级语言都支持Lambdajavajdk1.8以后才支持Lamda语法,LamdaKotlin的灵魂所在,此小节对Lambda的基础进行学习,并借助集合练习。

集合的创建和遍历

List
fun main() {//常规创建val list = ArrayList<Int>()list.add(1)list.add(2)list.add(3)//listOf不可变,后续不可添加删除,只能查val list1 = listOf<Int>(1, 2, 3 ,4 ,5)list1.add(6)//报错//mutableListOf,后续可添加删除val list2 = mutableListOf<Int>(1, 2, 3 ,4 ,5)list2.add(6)//循环for (value in list2) {println(value)}
}
Set

set用法与List类似,只是把listOf替换为mapOf

Map

fun main() {val map = HashMap<String, String>()map.put("1", "zjm")map.put("2", "ljn")//Kotlin中map支持类似下标的赋值和访问map["3"] = "lsb"map["4"] = "lyx"println(map["2"])println(map.get("1"))//不可变val map1 = mapOf<String, String>("1" to "zjm", "2" to "ljn")map1["3"] = "lsb" //报错//可变val map2 = mutableMapOf<String, String>("1" to "zjm", "2" to "ljn")map2["3"] = "lsb"for ((key, value) in map) {println(key + "   " + value)}}

Lambda

Lambda的使用
方法在传递参数时都是普通变量,而Lambda可以传递一段代码

Lambda表达式的语法结构

{参数名1: 参数类型, 参数名2:参数类型 -> 函数体}

Kotlin的list提供了maxByOrNull函数,返回当前list中xx最大的元素,XX是我们定义的条件,可能为长度,可能是别的,我们拿长度举例。

若不使用maxBy,实现如下

fun main() {val list = listOf<String>("a", "aba", "aabb", "a")var maxStr = ""for (str in list) {if (str.length > maxStr.length) {maxStr = str;}}println(maxStr)
}

maxByOrNull是一个普通方法,需要一个Lambda参数,下面结合Lambda使用maxByOrNull

fun main() {val list = listOf<String>("a", "aba", "aabb", "a")var lambda = {str: String -> str.length}var maxStr = list.maxByOrNull(lambda)println(maxStr)
}

直接当成参数也可传递

var maxStr = list.maxByOrNull({str: String -> str.length})

Lambda为方法的最后一个参数,则可将{}提到外面

var maxStr = list.maxByOrNull() {str: String -> str.length}

若有且仅有一个参数且是Lambda,则可去掉()

var maxStr = list.maxByOrNull {str: String -> str.length}

Kotlin拥有出色的类型推导机制,Lambda参数过多时可省略参数类型

var maxStr = list.maxByOrNull {str -> str.length}

Lambda只有一个参数,则可用it替代参数名

var maxStr = list.maxByOrNull {it.length}

集合还有许多此类函数

创建list,后续操作都由此list转换

val list = listOf<String>("a", "aba", "aabb", "a")

map 映射,返回新集合,将集合中的元素映射成另一个值

val newList = list.map { it.toUpperCase() }//将集合中的元素都准换成大写

filter过滤,返回新集合,将集合中的元素进行筛选

val newList = list.filter { it.length > 3 }//筛选出长度大于3的元素

any返回Boolean,集合中是否存在元素满足Lambda的条件,有则返回true,无则false

val isAny = list.any {it.length > 10} //返回false

all返回Boolean,集合中元素是否全部满足满足Lambda的条件,有则返回true,无则false

val isAll = list.all {it.length > 0} //返回true

Lambda的简单使用到这就结束了

Java函数式API的使用

Kotlin调用Java方法,若该方法接收一个Java单抽象方法接口参数,则可使用函数式APIJava单抽象方法接口指的是接口只声明一个方法,若有多个方法则无法使用函数式API

Java单抽象方法接口例如Runnable

public interface Runnable {void run();
}

Java中启动一个线程如下:

new Thread(new Runnable() {@Overridepublic void run() {System.out.println("test");}
}).start();

Kotlin启动线程如下:

Kotlin摒弃了new,若想声明匿名内部类必须使用object

Thread(object : Runnable {override fun run() {println("test")}
}).start()

RunnableJava单抽象方法接口,可对代码进行简化

Thread(Runnable {println("test")}).start()

Runnable接口只用一个方法,使用Lambda也不会有歧义,Kotlin知道此Lambda一定实现的为run函数,借用Lambda进一步简化:

Thread({println("test")
}).start()

又因Thread只需一个参数Runnable参数,则可省略()

Thread {println("test")
}.start()

与上类似的,click也使用上述方法

button.setOnClickListener { println("test") }

这种方式可极大缩减代码量

空指针检查机制

国外统计程序出现最多的异常为空指针异常,Kotlin存在编译时检查系统帮助我们发现空指针异常。

查看下面Java代码

public void doStudy(Study study) {study.doHomework();study.readBooks();
}

上述代码时存在空指针风险的,传入null,则程序崩溃,对其进行改进

public void doStudy(Study study) {if (study != null) {study.doHomework();study.readBooks();}
}

对于Kotlin来讲任何参数和变量不能为空

fun study(study: Study) {study.doHomework()study.readBooks()
}fun main() {study(null) //报错study(Student()) //正确
}

Kotlin把空指针异常的检查提前到了编译期,若空指针则编译期就会崩溃,避免在运行期出现问题

若我们有特殊的需求可能需要传递null参数,参数则按照下面声明

fun study(study: Study?) {study.doHomework() //报错study.readBooks()	//报错
}

?的意思则是当前参数可为空,如果可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下

fun study(study: Study?) {if (study != null) {study.doHomework()study.readBooks()}
}

也可借助判空辅助工具

判空辅助工具
?.

其含义是前面对象不为空才执行.后面的方法

fun study(study: Study?) {study?.doHomework()study?.readBooks()
}
?:

其含义是前不为空则返回问号前的值,为空则返回后的值

比如

val c = if (a !=null ) {a
} else {b
}

借助?:则可简化为

val c = a ?: b

再比如

fun getTextLength(text: String?): Int {if (text != null) {return text.length}return 0
}

借助?: 则可简化为

fun getTextLength(text: String?) = text?.length ?: 0
!!

有些时候我们想要强行通过编译,就需要依靠!!,这时就是程序员来保证安全

fun study(study: Study?) {//假设此时为空抛出异常,则和java一样study!!.doHomework()study!!.readBooks()
}

let函数

let不是关键字,而是一个函数,提供了函数式API的编程接口,会将调用者作为参数传递到Lambda表达式,调用之后会立马执行Lambda表达式的逻辑

obj.let { it -> //it就是obj//编写操作
}

比如上面函数

fun study(study: Study?) {study.doHomework()  //报错study.readBooks()	//报错
}

借助let则可改为

fun study(study: Study?) {//此时靠?.则保证了study肯定不为空,才会执行let函数study?.let {//it为studyit.doHomework()it.readBooks()}
}

全局判空注意事项

//全局变量
var study: Study? = null
fun study() {//报错if (study != null) {study.readBooks()study.doHomework()}
}

因全局变量随时有可能被其他线程修改,即使判空处理也不能保证其没有空指针风险,而let则可规避上述问题

var study: Study? = null
fun study() {study?.let {it.doHomework()it.readBooks()}
}

内嵌表达式 $

之前我们拼接字符串都是下面这样

var name = "zjm"
var age = 20
println("My name is " + name + ". I am " + age + ".")
//打印结果
//My name is zjm. I am 20.

现在靠着Kotlin提供的内嵌表达式则不需要拼接,只需要下面这样则可实现

var name = "zjm"
var age = 20
println("My name is $name. I am $age." )
//打印结果
//My name is zjm. I am 20.
内嵌表达式复杂操作

${程序员想要的操作}

var name = "zjm"
var age = 20
println("My name is ${if (1 < 2) "zjm" else "ljn"}. I am $age." )
//打印结果
//My name is zjm. I am 20.

函数的参数默认值

Kotlin支持函数存在默认值,使用如下

fun main() {myPrint(1)myPrint(1, "lalala")
}fun myPrint(value: Int, str: String = "hello") {println("num is $value, str is $str")
}//结果如下
//num is 1, str is hello
//num is 1, str is lalala

value想为默认值,则会报错,因为在使用时传入的第一个参数他认为是int的,传入字符串会类型不匹配

fun main() {myPrint("zjm")//报错
}fun myPrint(value: Int = 100, str: String) {println("num is $value, str is $str")
}

Kotlin提供了一种键值对传参来解决上述问题

fun main() {myPrint(str = "zjm") //正确调用
}fun myPrint(value: Int = 100, str: String) {println("num is $value, str is $str")
}

回顾之前的主次构造,Student如下

class Student(name: String,  age: Int, val number: String, val grade: Int) : Person(name, age){constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {}...
}

上述的此构造借助参数默认值技巧是可以不写的,将第四个参数默认值为0 即可

class Student(name: String,  age: Int, val number: String, val grade: Int = 0) : Person(name, age){...
}

by lazy

Kotlin 的 by lazy 是一种​​延迟初始化属性​​的委托机制,主要用于优化资源加载、减少启动开销,并简化代码逻辑

1. ​​基本特性与工作原理​
  • ​延迟初始化​​:by lazy 定义的属性仅在首次访问时执行初始化逻辑,后续访问直接返回缓存值。
  • ​只读属性​​:仅适用于 val(不可变变量),初始化后值不可修改。
  • ​线程安全​​:默认使用 LazyThreadSafetyMode.SYNCHRONIZED 模式,通过双重检查锁(double-checked locking)确保多线程安全
// 默认线程安全模式
val database: Database by lazy {Database.connect("jdbc:mysql://localhost:3306/mydb")
}
 ​​Android 中的典型应用场景​
  • ​ViewModel 初始化​​:推迟创建直到首次访问,避免 Activity/Fragment 构造时的额外开销
class MainActivity : AppCompatActivity() {private val viewModel by lazy { ViewModelProvider(this).get(MainViewModel::class.java) }
}
  • 高开销资源​​:如数据库连接、文件读取或网络客户端。
  • ​按需加载视图​​:仅在需要时初始化复杂 UI 组件(如自定义控件)。

lateinit

Kotlin 的 lateinit 是一种​延迟初始化非空可变属性​的机制,主要用于解决对象在声明时无法立即赋值但后续保证会被初始化的问题

可变属性​

  • 仅适用于 var 变量,不可用于 val(常量)。
  • ​非空类型限制​​:只能用于对象类型(如 StringView),​​不支持原始数据类型​​(如 IntBoolean

Android 中的典型应用场景​

  1. ​视图绑定与控件初始化​

    • 在 Activity/Fragment 的 onCreate() 中初始化 View,避免声明时立即加载资源
class MainActivity : AppCompatActivity() {lateinit var binding: ActivityMainBindingoverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater) // 手动初始化setContentView(binding.root)}
}

2.ViewModel 属性赋值​

  • 在 ViewModel 中声明非空属性,并在 Activity 中通过 ViewModelProvider 赋值
class MyViewModel : ViewModel() {lateinit var userData: String // 稍后由 Activity 赋值
}

by lazy与 lateinit 的对比​

by lazy 和 lateinit 均用于延迟初始化,但适用场景不同:

​特性​by lazylateinit
​适用变量类型​val(只读)var(可变)
​初始化时机​首次访问时自动初始化需手动显式初始化
​线程安全​默认支持(可配置模式)无内置线程安全
​支持数据类型​所有类型(含基本类型)仅非空对象类型(不含 Int 等)
​典型场景​单例、高开销资源、只读配置Android 视图绑定、依赖注入
http://www.dtcms.com/a/316158.html

相关文章:

  • 让 Spark 干体力活:用 Java 快速找出最小值
  • GaussDB 并行创建索引
  • Webpack 5 Module Federation 模块共享最佳实践
  • AI智能体的安全困境:防护机制与伦理平衡的艺术
  • 高精度惯性导航IMU传感器供应商价格
  • Python-机器学习初识
  • C结构体的几种定义形式 + typedef结合使用的好处
  • 数分思维14:用户研究与数据分析
  • WordPress如何实现隐藏文章部分内容?WordPress无法解析[hide]...[/hide]这类短代码怎么办?
  • 【机器学习】算法调参的两种方式:网格搜索(枚举)、随机搜索
  • Android 中几种常用布局的优缺点
  • 2023 年 6 月 GESP Python 二级试卷真题+答案+解析
  • 基于 Lyapunov 能量函数的等势面绘制方法 —— MATLAB 实现与工程应用拓展
  • 永磁同步电机的矢量控制
  • CPP引用
  • 组织架构与软件架构协同演进实践指南
  • UE5 安装Visual Studio
  • Go语言实战案例:使用context控制协程取消
  • GB28181监控平台LiveGBS如何配置GB28181对接海康、大华解码器上墙,将GB28181平台是视频给硬件解码器解码上墙
  • 软件无线电 招标参数
  • ⭐CVPR2025 非均匀运动视频插帧新突破
  • 文献阅读 | Briefings in Bioinformatics | Hiplot:全面且易于使用的生物医学可视化分析平台
  • HarmonyOS 应用拉起系列(二):如何拉起微信小程序
  • 前端1.0
  • 查看 Redis 某个数据库的内存占用
  • python+MySQL组合实现生成销售财务报告
  • 站在前端的角度,看鸿蒙页面布局
  • MTK-Android 系统拷贝预置资源
  • 本地使用uv管理的python项目怎么部署到服务器?
  • Next.js 链接与导航:页面间无缝切换