Kotlin学习日记(五)类的多种多样
类有自己的一些特性,有些类有特有的功能,都是为了更好地解决问题。
枚举类
跟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() 函数
具体看文档吧,这里东西比较多。