美文网首页
kotlin基础(二)

kotlin基础(二)

作者: 醉了俗身醒了初心 | 来源:发表于2019-05-29 09:12 被阅读0次

    kotlin控制语句

    if else 语句

     // 传统用法
    var max = a 
    if (a < b) max = b
     
    // 使用 else 
    var max: Int
    if (a > b) {
        max = a
    } else {
        max = b
    }
     
    // 作为表达式
    val max = if (a > b) a else b //类似于java中的三元运算符, kotlin中没有三元运算符
    //  我们也可以把 IF 表达式的结果赋值给一个变量。
    
    val max = if (a > b) {
        print("Choose a")
        a
    } else {
        print("Choose b")
        b
    }
    

    使用区间 使用 in 运算符来检测某个数字是否在指定区间内.

    //区间格式为 x..y :
    val x = 5 
    val y = 9 
    if (x in 1..8) { 
       println("x 在区间内") 
    }
    

    When 表达式 类似于Java中的switch表达式, 但是远比它强大, 支持所有数据类型

    // 其最简单的形式如下: 
    when (x) {
        1 -> print("x == 1")
        2 -> print("x == 2")
        else -> { // 注意这个块 在打括号内可以执行多行代码
            print("x 不是 1 ,也不是 2")
        }
    }
    
    //  在 when 中,else 同 switch 的 default。如果其他分支都不满足条件将会求值 else 分支。
    
    //  如果很多分支需要用相同的方式处理,则可以把多个分支条件放在一起,用逗号分隔:
    
    
    when (x) {
        0, 1 -> print("x == 0 or x == 1")
        else -> print("otherwise")
    }
    //  检测一个值在(in)或者不在(!in)一个区间或者集合中: 
    when (x) {
        in 1..10 -> print("x is in the range")
        in validNumbers -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
    // 另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,
    // 你可以访问该类型的方法和属性而无需 任何额外的检测。
    fun hasPrefix(x: Any) = when(x) {
        // is 类似于Java中的instanceof 用来判断数据类型 和java不同的是, 使用is判断过类型后, 不用再强转数据类型, 
        // 可以智能转换
        is String -> x.startsWith("prefix") 
        else -> false
    }
    // when 也可以用来取代 if-else if链。 如果不提供参数,所有的分支条件都是简单的布尔表达式,
    
    // 而当一个分支的条件为真时, 则执行该分支:
    when {
        x.isOdd() -> print("x is odd")
        x.isEven() -> print("x is even")
        else -> print("x is funny")
    }
    

    for循环, for 可以循环遍历任何提供了迭代器的对象。 数组, 区间(0..10), 集合, Map等

    //语法: 
    for (item in collection) {
       print(item)
    }
    
    //通过索引遍历数组
    for (i in array.indices) {
        print(array[i])
    }
    
    //对集合进行遍历
    val items = listOf("apple", "banana", "kiwi")
    for (item in items) {
        println(item)
    }
     
    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
    
    //正常循环 1..4 或者1 until 5(不包含5)
    for (i in 1..4) print(i) // 打印结果为: "1234"
    
    //反序循环  4 downTo 1  包含头和尾
    for (i in 4 downTo 1) print(i) // 打印结果为: "4321"
    
    //也支持指定步长:关键字:step
    for (i in 1..4 step 2) print(i) // 打印结果为: "13"
    for (i in 4 downTo 1 step 2) print(i) // 打印结果为: "42"
    

    while 与 do...while 循环, return, break,contine 和java一样,

    //标签处返回, 稍有区别
    fun foo() {//显式标签
        ints.forEach lit@ {
            if (it == 0) return@lit
            print(it)
        }
    }
    fun foo() {
        ints.forEach {//隐式标签
            if (it == 0) return@forEach
            print(it)
        }
    } 
    

    类和对象

    类定义

    class Person { //默认public权限 // 大括号内是类体构成 }
    

    定义一个空类

    class Empty
    

    在类中定义成员函数:

    class Runoob() { fun foo() { print("Foo") } // 成员函数 }
    

    属性定义

    class Person{
    
         var name: String = "wwf" //默认public
    
         private var age: Int= 12//私有的属性
    
    }
    

    创建类实例:

    val person= Person() // Kotlin 中没有 new 关键字
    //属性调用
    person.name
    

    Koltin 中的类可以有一个 主构造器,以及一个或多个次构造器,主构造器是类头部的一部分,位于类名称之后:

    /*如果主构造器没有任何注解,也没有任何可见度修饰符,
    那么constructor关键字可以省略。*/
    class Person constructor(firstName: String) {//主构造器
    } 
    //等价于
    class Person(firstName: String) {} 
    
    /*没有主函数, 也可以如:自定义线性布局 ,
    继承使用 : 接口和类都是 : 类后面要添加(), 接口不用*/
    class MyLinearLayout : LinearLayout {
        
        constructor(context: Context) : super(context) {//次构造器
    
        }
    
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {//次构造器
    
        }
    
        constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : 
                 super(context, attrs, defStyleAttr) {//次构造器
    
        }
    }
    //等价于 有主构造函数, 可以不写次构造函数,
    

    @JvmOverloads 关键字告诉虚拟器生成java代码, 会生成java的三个构造函数

    //自定义线性布局
    class MyLinearLayout @JvmOverloads constructor(
            context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
        ) : LinearLayout(context, attrs, defStyleAttr){}
    

    getter 和 setter

    //属性声明的完整语法:
     var <propertyName>[: <PropertyType>] [= <property_initializer>]
        [<getter>]
        [<setter>]
    var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setter 可读可写
    val inferredType = 1   // 类型为 Int 类型,默认实现 getter 只读属性
    实例:
    
    class Person {
    
        var lastName: String = "zhang"
            get() = field.toUpperCase()   // 将变量赋值后转换为大写
            set
    
        var no: Int = 100
            get() = field                // 后端变量
            set(value) {
                if (value < 10) {       // 如果传入的值小于 10 返回该值
                    field = value
                } else {
                    field = -1         // 如果传入的值大于等于 10 返回 -1
                }
            }
    
        var heiht: Float = 145.4f
            private set
    }
    
    // 测试
    fun main(args: Array<String>) {
        var person: Person = Person()
    
        person.lastName = "wang"
    
        println("lastName:${person.lastName}")
    
        person.no = 9
        println("no:${person.no}")
    
        person.no = 20
        println("no:${person.no}")
    
    }
    

    非空属性必须在定义的时候初始化,kotlin提供了一种可以延迟初始化的方案,使用 lateinit 关键字描述属性:

     class MyLinearLayout @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
    ) : LinearLayout(context, attrs, defStyleAttr) {
    
        private lateinit var mContext: Context//成员属性 不可为空
        
        private lateinit var mText: String//成员属性 不可为空 
        //也可以这样声明 private var mText : String? = null 可空属性
        
        fun setText(text: String) {
            this.mText = text
        }
        init {//构造函数初始化
            this.mContext = context
        }
        fun test(){
         //声明时, 带? 使用时, 也要带? 和Java if(mText == null){} 等价
         //使用lateinit(延迟初始化, 使用前, 必须初始化, 否则报异常)声明的变量使用时, 不用加? 但是会报空指针异常
          mText?.plus("你好")
        }
       
    }
    

    抽象类, 抽象是面向对象编程的特征之一,类本身,或类中的部分成员,都可以声明为abstract的。

          //抽象成员在类中不存在具体的实现。
    
          注意:抽象类和接口, 默认是open修饰的, 普通类默认final类,
           不能被继承。 所有类, 不加public默认都是public权限
    
         open class Base {
    
           open fun f() {
    
           }
    
         }
    
         abstract class Derived : Base() { 
    
            override abstract fun f()
    
         }
    

    嵌套类

     class Outer {                  // 外部类
        private val bar: Int = 1
        class Nested {             // 嵌套类
            fun foo() = 2
        }
    }
    
    fun main(args: Array<String>) {
        val demo = Outer.Nested().foo() // 调用格式:外部类.嵌套类.嵌套类方法/属性
        println(demo)    // == 2
    }
    

    内部类

     内部类使用 inner 关键字来表示。
    
    内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
    
     class Outer {
        private val bar: Int = 1
        var v = "成员属性"
        /**嵌套内部类**/
        inner class Inner {
            fun foo() = bar  // 访问外部类成员
            fun innerTest() {
                var o = this@Outer //获取外部类的成员变量
                println("内部类可以引用外部类的成员,例如:" + o.v)
            }
        }
    }
    
    fun main(args: Array<String>) {
        val demo = Outer().Inner().foo()
        println(demo) //   1
        val demo2 = Outer().Inner().innerTest()   
        println(demo2)   // 内部类可以引用外部类的成员,例如:成员属性
    }
    

    匿名内部类

     class Test {
        var v = "成员属性"
    
        fun setInterFace(test: TestInterFace) {
            test.test()
        }
    }
    

    定义接口

    interface TestInterFace {
        fun test()
    }
    
    fun main(args: Array<String>) {
        var test = Test()
    
        /**
         * 采用对象表达式来创建接口对象,即匿名内部类的实例。
         */
        test.setInterFace(object : TestInterFace {
            override fun test() {
                println("对象表达式创建匿名内部类的实例")
            }
        })
    }
    

    click点击事件

    mTextView?.setOnClickListener {//大括号内使用 it 代指调用者
       //里面处理点击事件
    }
    

    修饰符

     类的修饰符包括 classModifier 和_accessModifier_:
    
    // classModifier: 类属性修饰符,标示类本身特性。
    
    kotlin                                       java
    abstract    // 抽象类                         abstract
    final       // 类不可继承,默认属性            final
    enum        // 枚举类                         enum
    open        // 类可继承,类默认是final的       没被final修饰的类
    annotation  // 注解类                         annotation
    accessModifier: 访问权限修饰符
    
    kotlin                                       java
    private    // 仅在同一个文件中可见             private
    protected  // 同一个文件中或子类可见           protected
    public     // 所有调用的地方都可见             public
    internal   // 同一个模块中可见                 没有修饰符,
    

    继承 Any所有类的超类, 类似于java中的Object
    Kotlin 中所有类都继承该 Any 类,它是所有类的超类,对于没有超类型声明的类是默认超类:

     class Example // 从 Any 隐式继承
    Any 默认提供了三个函数: 
    
     equals()
    
    hashCode()
    
    toString()
     如果一个类要被继承,可以使用 open 关键字进行修饰。
    
     open class Base(p: Int)           // 定义基类
    
    class Derived(p: Int) : Base(p)
    如果子类有主构造函数, 则基类必须在主构造函数中立即初始化。 
    
     open class Person(var name : String, var age : Int){// 基类
    
    }
    
    class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {
    
    }
    
    // 测试
    fun main(args: Array<String>) {
        val s =  Student("Runoob", 18, "S12346", 89)
        println("学生名: ${s.name}")
        println("年龄: ${s.age}")
        println("学生号: ${s.no}")
        println("成绩: ${s.score}")
    }
    

    子类没有主构造函数
    如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

     class Student : Person {
    
        constructor(ctx: Context) : super(ctx) {
        } 
    
        constructor(ctx: Context, attrs: AttributeSet) : super(ctx,attrs) {
        }
    }
    

    重写: 在基类中,使用fun声明函数时,此函数默认为final修饰,不能被子类重写。如果允许子类重写该函数,那么就要手动添加 open 修饰它(抽象函数除外, 默认是open的), 子类重写方法使用 override 关键词:

     /**用户基类**/
    open class Person{
        open fun study(){       // 允许子类重写
            println("我毕业了")
        }
    }
    
    /**子类继承 Person 类**/
    class Student : Person() {
    
        override fun study(){    // 重写方法
            println("我在读大学")
        }
    }
    
    fun main(args: Array<String>) {
        val s =  Student()
        s.study();
    
    }
    

    属性重写 :
    属性重写使用 override 关键字,属性必须具有兼容类型,每一个声明的属性都可以通过初始化程序或者getter方法被重写:

     open class Foo {
        open val x: Int get { …… }
    }
    
    class Bar1 : Foo() {
        override val x: Int = ……
    }
    

    你可以用一个var属性重写一个val属性,但是反过来不行。因为val属性本身定义了getter方法,重写为var属性会在衍生类中额外声明一个setter方法
    你可以在主构造函数中使用 override 关键字作为属性声明的一部分:

     interface Foo {
        val count: Int
    }
    
    class Bar1(override val count: Int) : Foo
    
    class Bar2 : Foo {
        override var count: Int = 0
    }
    

    接口

    Kotlin 接口与 Java 8 类似,使用 interface 关键字定义接口,允许方法有默认实现

     interface Demo{
        fun add(a:Int, b:Int):Int    // 未实现
        fun minus(a: Int, b: Int): Int {  //已实现
            return a - b
        }
    }
    

    一个类或者对象可以实现一个或多个接口

    class SubDemo: Demo{
    
        override fun add(a:Int, b:Int) : Int {
    
             // 方法体
    
        }
    
    }
    

    接口中的属性只能是抽象的,不允许初始化值,接口不会保存属性值,实现接口时,必须重写属性

     interface Demo {
        var name:String 
    }
    
    class SubDemo : Demo{
        override var name:String = "wwf"//重写属性
    }
    

    函数重写: 实现多个接口时,可能会遇到同一方法继承多个实现的问题。例如:

     interface Demo1{
        fun foo() { print("A") }   // 已实现
        fun bar()                  // 未实现,没有方法体,是抽象的
    }
    
    interface Demo2 {
        fun foo() { print("B") }   // 已实现
        fun bar() { print("bar") } // 已实现
    }
    
    class Demo3 : Demo1 {
        override fun bar() { print("bar") }   // 重写
    }
    
    class Demo4 : Demo1, Demo2 {
        override fun foo() {
            super<Demo1>.foo()
            super<Demo2>.foo()
        }
    
        override fun bar() {
            super<Demo2>.bar()
        }
    }
    
    fun main(args: Array<String>) {
        val d =  Demo4()
        d.foo()
        d.bar()
    }
    

    相关文章

      网友评论

          本文标题:kotlin基础(二)

          本文链接:https://www.haomeiwen.com/subject/nujrtctx.html