发布于 2026-01-06 2 阅读
0

Kotlin - 入门 最接近的答案是 Kotlin。经典变量 var 和 val,Null 和 !!、?.、?: 函数,模式匹配(又称类型检查),类型转换

Kotlin 入门指南

最接近的答案是Kotlin……

克拉西

var 和 val

空字符和 !!、?.、?:

函数

模式匹配(又称类型检查)

类型铸造

如果我们创造一种语言,将其他流行语言的优点都吸收进去,会怎么样呢?

最接近的答案是Kotlin……

Kotlin 目前越来越受欢迎。根据这份报告,Kotlin 是增长速度第四快的编程语言。

让我们一起来探究一下。


如果你之前用的是Java,Kotlin能让你编写更少的代码。它能去除所有冗余代码,让你的代码优雅简洁。

例如,您可以编写一个简单的“Hello World”程序,如下所示:

println("Hello World!!!")
Enter fullscreen mode Exit fullscreen mode

如果你觉得它看起来像脚本语言,那么你的感觉很可能是对的。但主要区别在于 Kotlin 是一种静态类型编译型语言。当我们执行上面的println函数时,该函数会被编译并执行。

fun编写 Kotlin 函数是这样的:

fun hello() {
  println("Hello World!!!")
}
Enter fullscreen mode Exit fullscreen mode

没有分号 🎉

无需定义类 🎉💥

无需默认修饰符 🎉💥✨

上述函数是一个package-level函数。当我们将代码反编译成 Java 代码时,它将是final staticKotlin 根据文件名自动生成的类中的一个函数。

克拉西

太好了,我喜欢类,请问在 Kotlin 中如何定义类?

Kotlin 让它再次变得优雅简洁:

class Greeting
Enter fullscreen mode Exit fullscreen mode

就是这样,这就是一个类定义,甚至不需要用花括号来限定作用域。编译器会处理一切。

Greeting 类final默认是一个类。如果你想知道为什么,请回想一下经典的《Effective Java》定义。

让我们在类内部定义函数。


class Greeting {
  fun sayHello(): String {
    return "Hello"
  }

  fun sayHelloWithName(name: String) = "Hello $name"
}

Enter fullscreen mode Exit fullscreen mode

sayHello是一个经典的函数,它返回一个StringHello 对象。请注意,我们使用 `{{ return type }}` 符号定义了返回类型: String

第二个函数接受一个sayHelloWithName参数。由于它是一个单行函数,我们可以使用`&` 符号,后跟它的返回值。Kotlin 再次力求减少样板代码。nameString=

Kotlin 通过消除样板代码,让您享受编写代码的过程。但请记住,编译器会为您完成这些工作。这意味着 Kotlin 的编译时间会比 Java 更长。


构造函数

在面向对象编程中,类代表对象。对象拥有成员函数和构造函数来初始化自身。

例如,如果您想创建一个带有构造函数的员工类。

class Employee (name: String, salary: Long)
Enter fullscreen mode Exit fullscreen mode

这被称为主构造函数。

我们可以初始化员工:

val employee = Employee("Raj", 100000L)
Enter fullscreen mode Exit fullscreen mode

注意:没有new用于初始化对象的关键字。

如果您想为一些入职时已具备一定经验的员工添加经验字段,该怎么办?我们将使用secondary constructors……

Kotlin 提供了一种使用关键字定义多个构造函数的方法constructor

class Employee (name: String, salary: Long) {
  constructor(name: String, salary: Long, experience: Int): this(name, salary)
}
Enter fullscreen mode Exit fullscreen mode

我们使用关键字定义了辅助构造函数,constructor后跟输入参数列表。

注意:当定义了辅助构造函数和主构造函数时,我们应该将辅助构造函数委托给主构造函数。

我们不能在主构造函数中定义代码。这意味着,如果您想在初始化期间定义任何代码,则必须使用 ` constructorinit` 方法或 ` initset` 方法。

init 方法在类初始化时调用。

class Employee (name: String, salary: Long) {
  init {
    println("Employee ${this.name} is added")
  }
}
Enter fullscreen mode Exit fullscreen mode

初始化方法将在辅助构造函数初始化之前调用。

init一个类中可以包含多个方法。这些init方法会按照定义顺序被调用。


遗产

Kotlin 为继承提供了简便的语法。

class Manager {}
Enter fullscreen mode Exit fullscreen mode

现在,Manager 类必须继承自 Employee 类。毕竟,他们都是员工,对吧。

class Manager: Employee() {}
Enter fullscreen mode Exit fullscreen mode

运行上述代码时,编译器会报错。主要原因是 Employee 类有一个带两个参数的主构造函数。我们需要像下面这样将参数传递给 Employee 类。

class Manager: Employee(name: String, salary: Long)
Enter fullscreen mode Exit fullscreen mode

但是等等,我们从哪里获取这些输入给父类呢?我们将通过 Manager 的主构造函数传递它们。

class Manager(name: String, salary: Long): Employee(name: String, salary: Long)
Enter fullscreen mode Exit fullscreen mode

当然,经理应该有自己的队伍吧?我们也会让他们过关的。

class Manager(name: String, salary: Long, team: List<Employee>): Employee(name: String, salary: Long)
Enter fullscreen mode Exit fullscreen mode

但编译器仍然报错。Kotlin 默认将所有类声明为 final。

如果你想继承某个类,你应该open使用open关键字。如下所示。

open class Employee(name: String, salary: Long)

class Manager(name: String, salary: Long, team: List<Employee>): Employee(name: String, salary: Long)
Enter fullscreen mode Exit fullscreen mode

现在编译器很满意了。😃

Kotlin 还提供了sealed classes更多信息,请点击此处阅读。


数据类

冗余冗长的代码Plain Old Java Objects需要休息一下。Kotlin 的数据类使代码简洁明了,并消除了所有样板代码。不需要 ` gettersand` 和` settersor`。

data class User(val name: String, val age: Int)
Enter fullscreen mode Exit fullscreen mode

编译器会自动创建所有内容。


var 和 val

在 Kotlin 中,不可变类型是库内置的。你定义的类是 final 的,方法也是 final 和 static 的。

要定义一个不可变值,我们使用关键字val

val message = "Hello"
Enter fullscreen mode Exit fullscreen mode

一旦定义val,它就是不可更改的。

然而,Kotlin 作为一种友好的语言,也为您提供了var……

用 定义的值var是可变的。

var message = "Don't use me, it is a shame!!"
Enter fullscreen mode Exit fullscreen mode

空字符和 !!、?.、?:

Kotlin 强制你编写空安全代码。它会在编译时尝试消除空指针异常 (NPE)。

Kotlin 会编译成 Java 代码,然后再编译成 JVM 字节码。Java 有空指针异常(Null PointerException),因此可能会出现 NPE 的情况。

var message = "Hello"
message = null
Enter fullscreen mode Exit fullscreen mode

上述代码会出现编译错误,但null其他地方都正确。

在 Kotlin 中,我们可以使用 `Optional` 定义一个String?可以接受null值的 Optional 类型。

var message: String? ="Hello"
message = null
Enter fullscreen mode Exit fullscreen mode

上面的代码可以编译。但是当你在其他地方使用上面的代码时,例如

message.toUpperCase()
Enter fullscreen mode Exit fullscreen mode

编译器会发出警告。也就是说,Kotlin 编译器会在编译时阻止你调用可能为空的值。

我们可以使用以下任何一种语法来关闭编译器:

!!?.?:

第一个括号!!称为not-null assertion operator“或” dirty operator。双感叹号告诉编译器:“闭嘴编译,我知道自己在做什么。”

message!!.toUpperCase()
Enter fullscreen mode Exit fullscreen mode

这并不能防止运行时空指针异常。

?.被称为Safe-call operator。此运算符告诉编译器,如果值不为空,则调用该函数。

message?.toUpperCase()
Enter fullscreen mode Exit fullscreen mode

?.是糖语法

if (message != null) {
    message.toUpperCase()
}
Enter fullscreen mode Exit fullscreen mode

?:被称为elvis operator,它告诉编译器当不为空时执行此操作,否则执行另一操作。

message.toUpperCase() ?: "GIVE ME MESSAGE"
Enter fullscreen mode Exit fullscreen mode

?:是糖语法

if (message != null) {
    message.toUpperCase()
} else {
   "GIVE ME MESSAGE"
}
Enter fullscreen mode Exit fullscreen mode

函数

lambda

Kotlin 还允许在需要时轻松切换到函数式编程环境。在 Kotlin 中,函数是同等重要的组成部分。

这意味着什么first-class functions?这些函数可以用作表达式或数据结构,也可以通过参数和返回类型传递。


val evenNumbers = 0..100.toList().filter { number -> number % 2 == 0 }

Enter fullscreen mode Exit fullscreen mode

0..100.toList()创建一个包含 0 到 100 的列表。然后我们应用filter函数(我们不需要对stream它们进行操作)。

过滤器函数接受一个 lambda 函数作为参数。我们可以同时使用这两种()语法{}

然后,在 lambda 函数内部,我们检查是否为偶数并获取结果。最终返回的值是一个数字列表(你不需要处理collect这些数字)。

Kotlin 的确it简洁明了。上面的数字是多余的,我们可以用 `.` 去掉它it


val evenNumbers = 0..100.toList().filter { it % 2 == 0 }

Enter fullscreen mode Exit fullscreen mode

该值it代表列表中的当前值。

我们可以将不同的函数串联起来,进行进一步的变换。

虽然 Java 代码比较冗长,但 Kotlin 代码却简洁明了。

扩大

Kotlin 的一个突出特点是extension函数。假设你有一个类型Color,它接收一个十六进制字符串并将其转换为 RGB 值。你可以extension对一些基本类型(例如 `String`)创建类似下面的函数String

fun String.rgb() = this.removePrefix("#").windowed(2, 2).map { Integer.valueOf(it, 16) } // returns a list

println("#FFFFFF".rgb()) // 255, 255, 255

Enter fullscreen mode Exit fullscreen mode

那么这里会发生什么呢?

我们定义一个rgb扩展函数并将其附加到String基类。该扩展函数包含this一个参数,用于表示我们调用rgb方法所针对的值。然后,我们使用函数移除前缀removePrefix。移除前缀后,我们将字符串截取为 2 个字符的块,并将结果中的十六进制字符串转换为整数。最后,返回一个数字列表。

这段代码很优雅,而且作为字符串中定义的函数也十分自然。

注意:我们还可以使用函数覆盖现有功能extension。因此,请谨慎使用。

排队

我们可以inline在函数定义中添加关键字。这将使函数在调用点处以内联形式运行。

虽然内联可以提高应用程序的性能,但要注意,内联的函数越多,内存开销就越大。


模式匹配(又称类型检查)

我第一次接触到模式匹配时,Rust简直惊呆了。我一直都希望能在 JVM 中实现这个功能。但当时我既找不到也不知道有任何相关的实现。

使用 Kotlin,我们可以通过模式匹配来检查类型。这大大减少了类型转换和样板代码。无需手动转换对象,编译器会更高效地完成这项工作。

when (message) {
    is Int -> println("$message is a number")
    is String -> println("$message is a string")
    is Any -> println("${message} is any")
}
Enter fullscreen mode Exit fullscreen mode

那么这里发生了什么呢?is关键字用于模式匹配,它匹配消息类型。

当消息类型为 时IntInt调用该段。
当消息类型为 时StringString调用该段。
当消息类型为 时AnyAny调用该段。

这项功能即将在 Java 中推出——请查看我关于 Java 13 的文章(链接在此)。


类型铸造

我们可以使用关键字来转换对象的类型as

我们可以将一种类型转换为另一种类型,如下所示:

(1..10).toList().map { it as Any }
Enter fullscreen mode Exit fullscreen mode

Any`[Any]` 是基类型,它被定义为 Kotlin 类层次结构的根。每个 Kotlin 类都以 `[Any]` 作为超类。

所以我们正在使用关键字Integer进行类型转换Anyas

同样,我们也可以使用类型转换as?,这将提供safe-nullable类型转换。


点击此处查看这篇关于如何使用 KHipster 生成 Kotlin、React 和 Spring Boot 全栈应用程序的文章

想知道KHipster是什么吗?点击这里查看

你可以在推特上关注我。

如果你喜欢这篇文章,请点赞或留言。❤️

文章来源:https://dev.to/sendilkumarn/kotlin-for-developers-an-introduction-2kjg