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 ;

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

声明一个泛型类:

 //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)
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,265评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,274评论 1 288
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,087评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,479评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,782评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,218评论 1 207
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,594评论 2 309
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,316评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,955评论 1 237
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,274评论 2 240
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,803评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,177评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,732评论 3 229
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,953评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,687评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,263评论 2 267
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,189评论 2 258

推荐阅读更多精彩内容