欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Kotlin学习日记(五)类的多种多样

程序员文章站 2022-07-14 18:33:16
...

类有自己的一些特性,有些类有特有的功能,都是为了更好地解决问题。

枚举类

跟Java和其他语言的枚举类功能是一样的,可能用法和语法规则上有所不同。

enum class LogLevel(val id: Int){
    VERBOSE(0), DEBUG(1), INFO(2), WARN(3), ERROR(4), ASSERT(5);

    fun getTag(): String{
        return "$id, $name"
    }

    override fun toString(): String {
        return "$name, $ordinal"
    }
}

注解类

Kotlin的注解和Java差不多而且完全兼容。

声明注解类

annotation class 注解名

注解直接可以在类,函数,参数,变量,表达式,类型上等使用,一般起到了编译时检查和规范代码的作用。

内部类

在kotlin中也是有内部类的,总体上来说和java也差不多,但是有差别。

例子:

open class Outter{
    val a: Int = 0

    inner class Inner{
        val a: Int = 5

        fun hello(){
            println([email protected])
        }
    }

}

interface OnClickListener{
    fun onClick()
}

class View{
    var onClickListener: OnClickListener? = null
}

fun main(args: Array<String>) {
    val inner = Outter().Inner()

    val view = View()
    view.onClickListener = object : Outter(), OnClickListener{
        override fun onClick() {

        }
    }
}

内部类,添加关键字inner,这样就可以访问外部类的成员。

在内部类里面的成员和外部成员有相同的属性名的时候,可以使用一下这种方式调用来区分外部类和内部类:

println([email protected])

匿名内部类

在android里面这个东西一定不陌生,匿名内部类都是通过对象表达式创建的:

val view = View()
    view.onClickListener = object : Outter(), OnClickListener{
        override fun onClick() {

        }
    }

但是object:Outter(),onClickListener{}这行代码有点迷,实际上java和kotlin的匿名内部类的区别在这,kotlin的匿名内部类像不同的类一样,允许继承,java不行。

object

有些时候特定的这类事物只能有一个,比如只能有一个老婆,这要是多了,这天天的得多热闹。(๑•ᴗ•๑)

Kotlin中没有静态属性和方法,但是也提供了类似单里的功能,就是object这么个东西。

object AdminUser {
    val username: String = "admin"
    val password: String = "admin"
    fun getTimestamp() = SimpleDateFormat("yyyyMMddHHmmss").format(Date())
    fun md5Password() = EncoderByMd5(password + getTimestamp())
}

就这样一个简单的单例就写好了。

object可以在内部类与匿名内部类中使用。

伴生对象

kotlin中提供了伴生对象 ,用companion object关键字声明:

fun main(args: Array<String>) {
    val latitude = Latitude.ofDouble(3.0)
    val latitude2 = Latitude.ofLatitude(latitude)

    println(Latitude.TAG)
}

class Latitude private constructor(val value: Double){
    companion object{
        @JvmStatic
        fun ofDouble(double: Double): Latitude{
            return Latitude(double)
        }

        fun ofLatitude(latitude: Latitude): Latitude{
            return Latitude(latitude.value)
        }

        @JvmField
        val TAG: String = "Latitude"
    }
}

很像是java里面的静态方法,实际上只是想,并不是一样的,kotlin是与java完全兼容的,那么在java中如何调用ofDouble()方法和属性TAG呢?就像例子中的加了一个注解@JvmStatic @JvmField

sealed密封类

就像我们为什么要用enum类型一样,比如你有一个enum类型 MoneyUnit,定义了元、角、分这些单位。枚举就是为了控制住你所有要的情况是正确的,而不是用硬编码方式写成字符串“元”,“角”,“分”。

同样,sealed的目的类似,一个类之所以设计成sealed,就是为了限制类的继承结构,将一个值限制在有限集中的类型中,而不能有任何其他的类型。

在某种意义上,sealed类是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

要声明一个密封类,需要在类名前面添加 sealed 修饰符。密封类的所有子类都必须与密封类在同一个文件中声明(在 Kotlin 1.1 之前, 该规则更加严格:子类必须嵌套在密封类声明的内部):

sealed class Expression

class Unit : Expression()
data class Const(val number: Double) : Expression()
data class Sum(val e1: Expression, val e2: Expression) : Expression()
data class Multiply(val e1: Expression, val e2: Expression) : Expression()
object NaN : Expression()

使用密封类的主要场景是在使用 when 表达式的时候,能够验证语句覆盖了所有情况,而无需再添加一个 else 子句:

fun eval(expr: Expression): Double = when (expr) {
    is Unit -> 1.0
    is Const -> expr.number
    is Sum -> eval(expr.e1) + eval(expr.e2)
    is Multiply -> eval(expr.e1) * eval(expr.e2)
    NaN -> Double.NaN
// 不再需要 `else` 子句,因为我们已经覆盖了所有的情况
}
//测试代码:
fun main(args: Array<String>) {
    val u = eval(Unit())
    val a = eval(Const(1.1))
    val b = eval(Sum(Const(1.0), Const(9.0)))
    val c = eval(Multiply(Const(10.0), Const(10.0)))
    println(u)
    println(a)
    println(b)
    println(c)
}
输出:
1.0
1.1
10.0
100.0

data数据类

在 Kotlin 中,也有对应这样的领域实体类的概念,并在语言层面上做了支持,叫做数据类,相当于javaBean:

data class Book(val name: String)
data class Fook(var name: String)
data class User(
        val name: String,
        val gender: String,
        val age: Int
) {
    fun validate(): Boolean {
        return true
    }
}

这里的var/val是必须要带上的。因为编译器要把主构造函数中声明的所有属性,自动生成以下函数:

equals()/hashCode() 
toString() : 格式是 User(name=Jacky, gender=Male, age=10)
componentN() 函数 : 按声明顺序对应于所有属性component1()、component2() ...
copy() 函数

具体看文档吧,这里东西比较多。