Data class
我们在开发项目时,通常会有一些简单的POJO类,比如java bean,唯一的作用就是持有数据。在Kotlin中使用这种类型时更简单,不过我们要使用关键字data,如下:
data class User(val name: String, val age: Int)
编译器会自动的生成如下方法:
(1)equals()/hashCode(),这两个通常都是成对出现的
(2)toString(), 格式为:User(name=John, age=42)
(3)componentN()方法,我们无法直接使用,但在多变量直接赋值时编译器会自动用到这些方法
(4)copy()
如果你想使用data class的原生特性,需要遵守以下几点:
(1)主要构造方法需要至少一个参数
(2)主要构造方法中的所有参数必须用val 或 var标记
(3)不能是abstract、open、sealed(密封类)或inner(内部类)
(4)
通常我们可以给构造函数中的参数赋予默认值,从而来简化我们的使用。
data class User(val name: String = "", val age: Int = 0)
- copy方法
我们有时候会copy一个对象,在copy时属性变量的值可以不完全一样,如下:
val user = User("zhangsan", 21)
val userCopy = user.copy(age = 22) //name还是"张三",年龄是22
- 分解data对象的属性
data对象是可以它的各个属性分解出来的,这个在我们一些特定的场景会非常有用,data之所以能够分解用的就是componentN()方法,component1(),component2(),component3(),顺序和构造方法中参数的顺序保持一致。分解出来的顺序也要保持一致:
val user = User("zhangsan", 21)
val (name, age) = user
println("name is $name, age is $age")
打印结果为=========
name is zhangsan, age is 21
Sealed class 密封类
密封类更像是特殊的枚举类,但跟枚举类不同的是,枚举类是同一种类型的几个实例对象,而密封类则是几个继承sealed class的几个类,它们经常使用在when表达式中,如:
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (){
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
is NotANumber -> Double.NaN
}
嵌套类
跟java语法一样,kotlin的class内部也可以声明class,我们称之为嵌套类。嵌套类又分普通嵌套类和内部嵌套类,内部嵌套类用关键字inner修饰,两个的不同点是内部嵌套类中有一个外部类对象的应用。如下:
普通的嵌套类
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 2
}
}
val demo = Outer.Nested().foo() // == 2
内部嵌套类
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
val demo = Outer().Inner().foo() // == 1
在kotlin中也可以使用匿名内部类,要使用修饰符object。分两种情况来说明一下,一种是匿名内部类的父类是接口,另外一种是父类是抽象类。
(1)父类是接口的情况
interface Listener {
fun click()
}
fun setListener(listener: Listener ){
println("set up listener")
}
fun client(){
setListener(object : Listener {
override fun click(){
println("click !!!")
}
})
}
(2)父类是抽象类时:
abstract class Listener {
fun click()
}
fun setListener(listener: Listener ){
println("set up listener")
}
fun client(){
setListener(object : Listener() {
override fun click(){
println("click !!!")
}
})
}
枚举
kotlin中的枚举也用关键字enum,每个枚举都是枚举类的一个实例对象,每个枚举中间用逗号隔开。如下:
enum class Color {
RED,
GREEN,
BLUE
}
也可以有带参的构造方法,如
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
跟java一样,枚举内部也可以有抽象方法,并且每个枚举必须实现这个方法,如下
enum class Color(val rgb: Int) {
RED(0xFF0000){
override fun p() {
...
}
},
GREEN(0x00FF00){
override fun p() {
...
}
},
BLUE(0x0000FF){
override fun p() {
...
}
};
abstract fun p()
}
跟java类似,enum提供了几个方法,
(1)valueOf(value: String)可以让使用者通过枚举的名字获得该枚举实例;
(2)values() 可以获得该枚举列表
以上是enum提供的方法,另外还可以使用扩展方法enumValues() 获取某个枚举类型所有的枚举实例。
object表达式及声明
上面已经提到了,object表达式可以用在匿名内部类中。除了可以实现接口或抽象类,object还可以没有任何父类而仅仅是个object。如下:
fun foo(){
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
println(adHoc .x + adHoc .y)
}
object匿名内部类中可以使用外部的局部变量,而跟java不同的是外部的局部变量没有必要时final类型的。如:
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
// ...
}
object还可以用来声明,并且声明的类是一个单例的,需要注意的是必须是无参的构造方法。如:
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ...
}
val allDataProviders: Collection<DataProvider>
get() = // ...
}
//这样使用
DataProviderManager.registerDataProvider(...)
object 还可以和Companion 结合起来使用,通过这种方式可以实现一个class的单例,如下:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create()
但是companion object是一个companion 对象,其内部的属性和方法也不是static,但是我们可以用@JvmStatic注解来声明一个java static类型的属性和方法,
代理
java中的设计模式中有代理模式,在kotlin中使用代理模式很简单,使用by关键字就可以了。java中代理的类图很简单,代理类和被代理类实现同一个接口,代理类中的所有操作由代理类处理。同时代理类还有一些扩展的功能比如控制切入点等。下面例子说明怎么使用代理:
interface Base{
fun print()
}
class BaseImpl(val x: Int) : Base{
override fun print() { print(x) }
}
class DelegationImpl(b: Base) : Base by b
fun main(args: Array<String>){
val b = BaseImpl(12)
DelegationImpl(b).print()
}
打印结果为======
12