kotlin基础语法(三)

十六, kotlin扩展函数

Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 装饰者模式。

定义形式:

fun 数据类型.函数名称(参数1, 参数2...){//参数可为空
     函数体
}

实例:

class Animal
class KotlinDemo2{
    companion object {
        @JvmStatic
        fun main(args: Array<String>) {
            test()
        }
        private fun test(){
            val animal = Animal()
            animal.speak("你是动物")
        }
    }
}

fun Animal.speak(str:String){
    println(str)
}

为 MutableList 添加一个swap 扩展函数:

fun MutableList<String>.swap(a: Int, b: Int) {
    val tmp = this[a]     //  this 对应MutableList列表
    this[a] = this[b]
    this[b] = tmp
}
val list = mutableListOf<String>("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<String>){
    var str = null
    println(str.toString())
}
//输出结果 null

扩展属性: 扩展属性只能被声明为 val。

val <T> Array<T>.length: Int
    get() = size

fun main(args:Array<String>){
    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<String>) {
    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<String>) {
    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 ;

  • 数据类不可以声明为 abstractopensealed 或者 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泛型

声明一个泛型类:

//kotlin网络请求, 数据类型基类
class BaseBean<T>{
    var code:Int = 0
    var message:String =""
    var data:T? = null
    var dataList:MutableList<T>? = null
}

创建数据类型时, 必须添加泛型, 否则报错

val baseBean = BaseBean<LoginBean>() //这个和Java不同, 必须添加

在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。

以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:

fun main(args: Array<String>) {
    val age = 23
    val name = "runoob"
    val bool = true

    doPrintln(age)    // 整型
    doPrintln(name)   // 字符串
    doPrintln(bool)   // 布尔型
}

fun <T> doPrintln(content: T) {

    when (content) {
        is Int -> println("整型数字为 $content")
        is String -> println("字符串转换为大写:${content.toUpperCase()}")
        else -> println("T 不是整型,也不是字符串")
    }
}

泛型约束 java中的extend, 和super都没有了, kotin中使用 :随便举的例子, 只是用来入门

class BaseBean<T : BaseType> {
    var data: T? = null
}

open class BaseType {

}

class UserBean : BaseType() {

}
fun main(args: Array<String>) {
    val baseBean = BaseBean<UserBean>()
    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的<out T> ,Java的<? super T> 相当于 Kotlin的<in T>
//3、<out T>  只能生产(出参), <in T> 只能消费(入参)
//4、<out T>  只能生产的原因是编译器无法确认什么对象符合那个未知的 T 的子类型,只知道一定返回T,<in T>  只能消费的原因是无法确认T超类的具体类型
//5、<*>相当于java中的无泛型。对于 Foo <out T>,其中 T 是一个具有上界的协变类型参数,Foo <*> 等价于 Foo <out Any>;对于 Foo <in T>,其中 T 是一个逆变类型参数,Foo <*> 等价于 Foo <in Nothing>

十九, kotlin枚举类 了解

和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<String>) {
    var color:Color=Color.BLUE

    println(Color.values())
    println(Color.valueOf("RED"))
    println(color.name)
    println(color.ordinal)

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值