Kotlin语法(六)

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值