解构声明
在Kotlin中,解构声明允许你从一个对象或数组中提取多个变量。这是一个非常有用的特性,可以让你的代码更加简洁和清晰。
fun main() {
val (name, age) = Person("Jack", 20)
}
copy函数
有时候我们希望在已有对象的基础上稍作修改后获取另一个新的对象,这时copy函数就会变得很有用:
val person = Person("Json", 20)
val newPerson = person.copy(name = "Jack")
Pair和Triple
Pair和Triple是Kotlin为我们提供的内置数据类。Pair类有两个属性参数,我们常常使用中缀函数to来创建一个Pair对象:
val point = 10 to 100
5.密封类
在Kotlin中声明一个密封类使用关键字sealed,在类声明的时候将其放在关键字class之前。例如我们将某车厂所生产的车型定义成一个密封类,并扩展以下子类:
sealed class CarType
class Car : CarType()
class SUV : CarType()
class BUS : CarType()
密封类用来表示受限的类继承结构:当一个值为有限的几种类型、而不能有任何其他类型。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。使用密封类的一个好处是,当我们使用when作为表达式的时候,只要覆盖到该密封类的所有子类型,无需再编写else块:
fun main() {
println(getCarName(Car()))
}
fun getCarName(carType: CarType) : String {
return when(carType) {
is Car -> "Car"
is SUV -> "SUV"
is BUS -> "BUS"
}
}
// 输出
Car
密封类本身是抽象的,我们没有办法直接创建一个密封类的对象,在密封类的类体中可以为其定义抽象方法或者属性:
sealed class CarType {
abstract val name: String
abstract fun info() : String
}
6.枚举类
和Java语言一样,在Kotlin中我们声明一个枚举类使用关键字enum。如下代码示例,我们声明一个名为LoadState的枚举类:
enum class LoadState {
Success,
Failure
}
每个枚举常量都只存在一个实例。它们都拥有一个name属性和一个ordinal属性。name用来表示该枚举常量的名称,ordinal用来表示枚举常量在声明时的顺序。我们可以使用枚举类的values()方法来获取其所有常量所在的数组。如果你想获取枚举类中所有常量的信息,就可以这么写:
fun main() {
for(state in LoadState.values()) {
println("name = ${state.name}, index = ${state.ordinal}")
}
}
//输出
name = Success, index = 0
name = Failure, index = 1
当我们传入正确的枚举常量名称时:
fun main() {
println(LoadState.valueOf(LoadState.Success.name))
}
// 输出
Success
我们可以在主构造函数中给枚举类新增属性:
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
}
fun main() {
for(color in Color.values()) {
println(color.rgb)
}
}
// 输出
16711680
65280
255
7.operator关键字
在Kotlin中要重载一个操作符,我们使用关键字operator。而实现一个操作符的重载我们使用函数来完成,每一个可以重载的操作符都有一个固定的函数名与之对应。我们只要在相应的函数前加上operator关键字即可。比如说减操作符对应固定的函数名为minus,加操作符对应的函数名为plus。如下示例代码:
data class Weather(var temperature: Float) {
// 重载减运算符
operator fun minus(weather: Weather) : Weather {
return Weather(this.temperature - weather.temperature)
}
}
fun main() {
val lastDay = Weather(15.5f)
val today = Weather(21.5f)
val temperatureInterval = today - lastDay
println("今天和昨天的温度相差:${temperatureInterval.temperature}")
}
// 输出
今天和昨天的温度相差:6.0
我们声明了一个天气的数据类Weather,并在其主构造函数中声明了一个temperature的属性。在Weather的内部使用minus函数重载了减操作符。这样我们就可以让两个Weather对象进行相减的操作。关于操作符重载我们有两点需要注意:
- 1.
operator关键字和操作符重载对应的函数名是固定的,不可更改 - 2.重载函数的参数和返回值是可变的,这个需要我们根据实际的需求来
1.泛型基础
在Java编程思想中有这么一句话:“当你希望代码能够跨多个类工作时,使用泛型才有所帮助。”我觉得这句话很形象的描述了泛型的使用场景,其实在前面的一些文章内容中我们也时常涉及到泛型的使用,只是没有详细的去介绍它。
在一般的编程模式下,我们需要给任何一个变量指明一个具体的类型。而泛型允许我们在不指定具体类型的情况下进行编程。对于泛型的声明我们使用<T>语法,声明一个泛型方法,需要将<T>放在方法名之前。声明一个泛型接口或者是类,需要将<T>放在对应的接口名或类名后。然而大写字母T是一种常规写法,我们也可以使用别的大写字母来代替。如果你想让声明的泛型有实际意义,也可以采用多个大写字母组合的方式,如<VM>、<VP>。
2.泛型函数
定义一个泛型函数其实并不复杂,我们只需要将类型参数放在函数名之前即可。如下代码示例:
private fun <T> getData(data: T) : T {
return data
}
我们定义了一个泛型函数getData(),当我们在调用泛型函数getData()的时候,需要将参数类型紧跟在函数名后,并用<>括起来:
fun main() {
val result = getData<String>("study work hard")
println("result = $result")
}
// 输出
result = study work hard
Kotlin编译器强大的类型推导机制一样适用于泛型,当我们可以从参数中推断出其类型,在调用处我们也可以省略类型参数:
fun main() {
val result = getData("study work hard")
}
泛型约束
泛型约束在Java中也有明确的定义,我们可以给声明的泛型指定一个边界。<T extends BaseFragment>类似这样的Java代码我们应该都很熟悉。而在Kotlin中我们依然使用冒号来指定,如下代码示例,我们定义一个带有边界的泛型函数getInfo():
open class Person
class MiddlePerson : Person()
class YoungPerson : Person()
private fun <T: Person> getInfo(person: T) : T {
return person
}
reified的关键字
泛型的协变、逆变、类型投影、星投影
in位置只能作为方法的参数来使用,out位置只能作为方法的返回值来使用
1.委托的概念
委托是一种设计模式,它的基本概念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。例如我们下面这段代码就是一个简单的示例:
class NewList<out T>(private val list: MutableList<T>) {
fun isEmpty() = list.isEmpty()
fun add(item: @UnsafeVariance T) = list.add(item)
fun remove(item: @UnsafeVariance T) = list.remove(item)
fun myMethod() {
// some logic
}
}