数据类
我们经常创建一些只保存数据的类。 在 Kotlin 中,这叫做 数据类 并标记为 data:
//如果生成的类需要含有一个无参的构造函数,则所有的属性必须指定默认值。
data class User(val name: String = "", val age: Int = 0)
主构造函数内部定义的属性会自动生成一些函数(equals()/hashCode()
toString()等)。
如需在生成的实现中排除一个属性,请将其声明在类体中:
//在 toString()、 equals()、 hashCode() 以及 copy() 的实现中只会用到 name 属性
data class Person(val name: String) {
//不会自动生成data的相关函数
var age: Int = 0
}
copy() 函数实现复制一个对象改变它的一些属性,但其余部分保持不变。
val jack = User(name = "Jack", age = 1)
val olderJack = jack.copy(age = 2)
密封类
sealed 关键字开头的类
使用密封类的关键好处在于使用 when 表达式 的时候,如果能够验证语句覆盖了所有情况
sealed class MyColor {
class Yellow : MyColor()
class Red : MyColor()
class Black : MyColor()
}
fun evals(color: MyColor) =
when (color) {
is MyColor.Yellow -> println("yellow")
is MyColor.Red -> println("red")
is MyColor.Black -> println("black")
}//不需要使用else了
fun main(args: Array<String>) {
evals(MyColor.Black())
}
嵌套类与内部类
标记为 inner 的嵌套类为内部类,能够访问其外部类的成员。
内部类会带有一个对外部类的对象的引用:
class Outer {
private val bar: Int = 1
//无inner为嵌套类
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
匿名内部类
使用对象表达式创建匿名内部类实例:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { …… }
override fun mouseEntered(e: MouseEvent) { …… }
})
枚举类
枚举类的最基本的用法是实现类型安全的枚举:
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
//通过名称获取枚举常量
EnumClass.valueOf(value: String): EnumClass
//获取所有枚举常量
EnumClass.values(): Array<EnumClass>
内联类
在使用包装类的场景可以考虑使用内联类实现,它可以提升包装类的性能。
什么是包装类?
基本数据类型 —>包装类
boolean —> Boolean
char —> Character
byte—> Byte
short—> Short
long
Long
int —> Integer
float—> Float
double—> Double
右边的开头大写字母的就是包装类
通过inline 关键字来定义内联类
//内联类必须含有唯一的一个属性在主构造函数中初始化
inline class Password(val value: String)
对象表达式
要创建一个继承某个类型的匿名类的对象,我们会这么写:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*……*/ }
override fun mouseEntered(e: MouseEvent) { /*……*/ }
})
或者这样
class C {
// 私有函数,所以其返回类型是匿名对象类型
private fun foo() = object {
val x: String = "x"
}
// 公有函数,所以其返回类型是 Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // 没问题
val x2 = publicFoo().x // 错误:未能解析的引用“x”
}
}
Kotlin中的单例模式
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}
对象声明的初始化过程是线程安全的并且在首次访问时进行。
如需引用该对象,我们直接使用其名称即可:
DataProviderManager.registerDataProvider(……)
伴生对象可以用 companion 关键字标记:
class MyClass {
//也可以给伴生对象命名 Factory
companion object Factory {
fun create(): MyClass = MyClass()
}
}
//使用:
val instance = MyClass.create()
或者
val instance = MyClass.Factory.create()
伴生对象实现接口:
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
val f: Factory<MyClass> = MyClass
在 JVM 平台,如果使用 @JvmStatic 注解,你可以将伴生对象的成员生成为真正的静态方法和字段