Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 装饰者模式。
定义形式:
fun 数据类型.函数名称(参数1, 参数2...){//参数可为空
函数体
}实例:
class Animal
class KotlinDemo2{ companion object { @JvmStatic fun main(args: Array
) { test() } private fun test(){ val animal = Animal() animal.speak("你是动物") } } } fun Animal.speak(str:String){ println(str) } 为 MutableList 添加一个swap 扩展函数:
fun MutableList
.swap(a: Int, b: Int) { val tmp = this[a] // this 对应MutableList列表 this[a] = this[b] this[b] = tmp } val list = mutableListOf
("a", "b", "c", "d") list.swap(1, 3) println(list)
扩展函数中的this指向, 谁调用, 指向谁
扩展函数是静态解析的,并不是接收者类型的虚拟成员, 在调用扩展函数时,具体被调用的的是哪一个函数,由调用函数的的对象表达式来决定的,而不是动态的类型决定的:
open class Demo class SubDemo : Demo() fun Demo.test(){ println("Demo") } fun SubDemo.test(){ println("SubDemo") } //在主函数中执行 val demo = Demo() val subDemo = SubDemo() demo.test() subDemo.test() //输出结果 Demo SubDemo
若扩展函数和成员函数一致,则使用该函数时,会优先使用成员函数。
open class Demo{ fun test(){ println("我是成员函数") } } fun Demo.test(){ println("我是扩展函数") } //在主函数中执行 val demo = Demo() demo.test() //输出结果 我是成员函数
扩展空对象:在扩展函数内, 可以通过 this 来判断接收者是否为 NULL,这样,即使接收者为 NULL,也可以调用扩展函数
fun Any?.toString(): String { if (this == null) return "null" // 空检测之后,“this”会自动转换为非空类型 return toString() } fun main(arg:Array
){ var str = null println(str.toString()) } //输出结果 null
扩展属性: 扩展属性只能被声明为 val。
val
Array .length: Int get() = size fun main(args:Array ){ val arr = arrayOf(1, 2, 3, 4) println(arr.length) }
扩展属性允许定义在类或者kotlin文件中,不允许定义在函数中。初始化属性因为属性没有后端字段(backing field),所以不允许被初始化,只能由显式提供的 getter/setter 定义。
val Demo.name = "wwf" // 错误:扩展属性不能有初始化器
伴生对象扩展
class Base{ //伴生对象, 类似于java中的静态成员(静态属性,静态方法 ) companion object { var token: String = "2t5856698" //类似于普通静态属性 const val ITEM_ONE:Int = 1 //常量 fun test(){//类似于静态方法 } } } fun Base.Companion.demo() { println("伴随对象的扩展函数") } //伴生扩展属性 val Base.Companion.number:Int get(){ return 10 } //伴生扩展属性 val Base.Companion.number2:Int get() = 12 fun main(args: Array
) { Base.Companion.demo() println(Base.Companion.number) }
扩展的作用域
//扩展函数或属性定义在顶级包下: package com.wwf.demo class Base fun Base.test() { println("Base test") } //要使用所定义包之外的一个扩展, 通过import导入扩展的函数名进行使用: package com.wwf.demo2 import com.wwf.demo.Base import com.wwf.demo.test fun main(args: Array
) { test12(Base()) } fun test12(base: Base) { base.test() }
数据类 关键字: data
data class User(var name:String, var age:Int)
编译器会自动的从主构造函数中根据所有声明的属性提取以下函数:
equals()
/hashCode()
toString()
格式如"User(name=John, age=42)"
componentN() functions
对应于属性,按声明顺序排列copy()
函数数据类需要满足以下条件:
主构造函数至少包含一个参数。
所有的主构造函数的参数必须标识为
val
或者var
;数据类不可以声明为
abstract
,open
,sealed
或者inner
;数据类不能继承其他类 (但是可以实现接口)。
数据类以及解构声明
val maggie = User("maggie", 35) val (name, age) = maggie println("$name, $age") // prints "maggie, 35"
密封类 :sealed
密封类用来表示受限的类继承结构:当一个值为有限几种的类型, 而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合 也是受限的,但每个枚举常量只存在一个实例,而密封类 的一个子类可以有可包含状态的多个实例。
声明一个密封类,使用 sealed 修饰类,密封类可以有子类,但是所有的子类都必须要内嵌在密封类中。
sealed 不能修饰 interface ,abstract class(会报 warning,但是不会出现编译错误)
sealed class ItemType data class ItemOne(val number: Double) : ItemType() data class ItemTwo(val e1: ItemType, val e2: ItemType) : ItemType() object NotANumber : ItemType() fun eval(itemType: ItemType): Double = when (ItemType) { is ItemOne-> itemType.number is ItemTwo-> eval(itemType.e1) + eval(itemType.e2) NotANumber -> Double.NaN }
使用密封类的关键好处在于使用 when 表达式 的时候,如果能够 验证语句覆盖了所有情况,就不需要为该语句再添加一个 else 子句了
fun eval(itemType: ItemType): Double = when(itemType) { is Expr.ItemOne-> itemType.number is Expr.ItemTwo -> eval(itemType.e1) + eval(itemType.e2) Expr.NotANumber -> Double.NaN // 不再需要 `else` 子句,因为我们已经覆盖了所有的情况 }
声明一个泛型类:
//kotlin网络请求, 数据类型基类 class BaseBean
{ var code:Int = 0 var message:String ="" var data:T? = null var dataList:MutableList ? = null }
创建数据类型时, 必须添加泛型, 否则报错
val baseBean = BaseBean<LoginBean>() //这个和Java不同, 必须添加
在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:
fun main(args: Array
) { val age = 23 val name = "runoob" val bool = true doPrintln(age) // 整型 doPrintln(name) // 字符串 doPrintln(bool) // 布尔型 } fun doPrintln(content: T) { when (content) { is Int -> println("整型数字为 $content") is String -> println("字符串转换为大写:${content.toUpperCase()}") else -> println("T 不是整型,也不是字符串") } }
泛型约束 java中的extend, 和super都没有了, kotin中使用 :随便举的例子, 只是用来入门
class BaseBean
{ var data: T? = null } open class BaseType { } class UserBean : BaseType() { } fun main(args: Array ) { val baseBean = BaseBean () val userBean : UserBean? = baseBean.data }
默认上界为Any
型变:分为两种, 协变和逆变 即 in out两种, 类似于java中的
super T> 和 extends T>, 理解为生产者和消费者
out 用作出参, 如返回值, in 入参, 用作传入的参数
星投影: * Kotlin中能省略泛型如集合泛型, 使用*代表不加泛型
List list = new ArrayList(); //java中
val list : ArrayList<*> = arrayListOf(1) // kotlin中, 必须初始化至少一个值, 不然报错
//1、 Kotlin的泛型使用基本和Java一致
//2、 Java的 extends T> 相当于 Kotlin的 ,Java的 super T> 相当于 Kotlin的
//3、 只能生产(出参), 只能消费(入参)
//4、 只能生产的原因是编译器无法确认什么对象符合那个未知的 T 的子类型,只知道一定返回T, 只能消费的原因是无法确认T超类的具体类型
//5、<*>相当于java中的无泛型。对于 Foo ,其中 T 是一个具有上界的协变类型参数,Foo <*> 等价于 Foo ;对于 Foo ,其中 T 是一个逆变类型参数,Foo <*> 等价于 Foo
和java类似
enum class Color{ RED,BLACK,BLUE,GREEN,WHITE }
枚举初始化
enum class Color(val rgb: Int) { RED(0xFF0000), GREEN(0x00FF00), BLUE(0x0000FF) }
enum class Shape(value:Int){ ovel(100), rectangle(200) }
enum class ProtocolState { WAITING { override fun signal() = TALKING }, TALKING { override fun signal() = WAITING }; abstract fun signal(): ProtocolState }
获取枚举相关信息:
val name: String //获取枚举名称 val ordinal: Int //获取枚举值在所有枚举数组中定义的顺序
fun main(args: Array
) { var color:Color=Color.BLUE println(Color.values()) println(Color.valueOf("RED")) println(color.name) println(color.ordinal) }