Kotlin学习05

作者: 咸鱼佬 | 来源:发表于2017-05-30 20:52 被阅读71次

    导语

    上一篇学习了Kotlin的函数,这一篇介绍函数的类。记得在一个包内(一个kt文件中),我们可以直接声明类,对象,属性,接口,函数...

    任务

    1. 类(接口)声明

    类(接口)声明##

    声明一个类(接口)很简单,class是修饰类的标识符

    package xian.yu.lao
    
    /**
     * Created by jinxiong on 2017/5/30.
     */
    
    public class Test1 {}//默认可见度是public,可不写public
    
    private class Test2 {}//私有
    internal class Test3 {}//module可见
    //protected class Test4{}//protected不可修饰顶级类(前面说过)
    final class Test4 {}//默认是final ,不可继承
    
    open class Test5 {}//可被其他类继承
    
    abstract class Test6 {}//默认是open(可继承)
    interface Test7 {}//默认是open(可实现)
    
    data class DataClass{}//数据类
    //枚举类,每个枚举常数都是一个一个对象(Test8的对象),而不能再new出Test8 的对象
    //不可继承,不可用open修饰
    enum class Test8() {
        A, B, C, D
    }
    
    //封闭类,算是枚举类的扩展
    //不可被外部继承,不可open修饰,不可再创建一个实例
    sealed class Test9 {
        //继承后面再说
        open class Const() : Test9() {}//继承Test9,可用open修饰,可被外部继承
    
        open class Sum() : Test9() {}//继承Test9
    }
    
    //嵌套类
    class Test10 {
        val a: Int = 1
    
        class Nested {
            fun tt(): Unit {
    //            println(a)//不可访问外部类的变量
            }
        }
    }
    
    //内部类
    class Test11 {
        val a: Int = 1
    
        inner class Nested {
            fun tt(): Unit {
                println(a)//可以访问外部类的变量
            }
        }
    }
    
    fun test(listener: Test7): Unit {
    
    }
    
    fun main(args: Array<String>) {
        
        test(object : Test7 {})//创建了一个匿名类的实例,类似于java中new 一个接口一样
    }
    

    上面列举了,final类,open类,接口,抽象类,枚举类,封闭类,嵌套类,内部类,匿名类,数据类
    下面讲下感觉比较陌生的类

    封闭类

    用来表示类层次的限制,就是限定某个值的类型只能是提供的一堆类型中的一个,不能是其他类型。可以说是枚举类的的扩展,枚举类的值数量是有限的,而封闭类中的子类也是有限的,而对于枚举类中的常量值,它代表着一个枚举类的实例(也就是说这个枚举类的实力个数基本定死),而对于封闭类,它子类可以被创建不定数量的实例
    封闭类用于when表达式非常的好,先介绍kotlin中的when

    when

    kotlin的when相当于Java中的switch

    when(变量){
        变量所属类型的一个值或一个范围 -> 后续代码(块)
        ..
        ..
        ..
        else -> 后续代码(块)//
    }
    //demo
    val a = 12
    when (a) {
        in 1..9 -> {
            println()
        }
        10 -> 12
        in 10..20 -> {
            println()
        }
    }
    

    当when作为表达式的时候必须要加上else(相当于switch的default

    fun ty(a: Int): Int = when (a) {
        12 -> 11
        else -> 10
    }
    

    上面中的 in是一个标识符,用于表示是否在某个集合中,在for循环中也有用到,后续再说for循环

    而-> 就相当于 如果符合啥条件就执行我后面的代码吧


    回到sealed类中,在上面的sealed类的定义中,我们说可以限定某个值只能是给定的一堆类型中的一中类型,在when中使用的好处就是无论什么情况都不用写else,因为那个值的属性只能是给定的集合中的某一个类型

    //对应上面的枚举类和封闭类
    //对于枚举类,就是判断变量是哪个实例 
    fun ty(a: Test8): Int = when (a) {
        Test8.A -> 1
        Test8.B -> 2
        Test8.C -> 3
        Test8.D -> 4
    }
    //对于封闭类,就是这个变量实例属于哪个子类
    fun tts(a: Test9): Int = when (a) {
        is Test9.Const -> 2
        is Test9.Sum -> 2
    }   
    

    内部类

    内部类要讲的主要是this的问题

    //内部类
    class Test11 {
        val a: Int = 1
    
        inner class Nested {
            fun tt(): Unit {
                println(a)//可以访问外部类的变量
            }
        }
    }
    

    我们知道在内部类中能够访问到外部类的变量,是因为在我们的内部类中存在着一个外部类的实例,对吧,那么当我们在内部类中使用this的时候是代表内部类还是外部类呢?
    还记得前面说过的return吗,带标签和不带标签。在这里是否也是可以这样解决这问题?
    so,也是可以使用标签解决的

    class Test11 {
        val a: Int = 1
    
        inner class Nested {
            val a = 2
            fun tt(): Unit {
                println(this@Test11.a)//访问Test11 中的a
                println(this.a)//访问inner中的a
            }
        }
    }
    

    规定在inner class中使用this是指inner实例,而使用外部类的this,就需要在this后面加上@类名,特别的,对于访问inner class中的成员(属性和函数),this可以省略,当和外部类命名冲突时,不加标签使用的都是inner class的成员

    匿名类

    我们在Java中写匿名类是这么写的

    View.setOnClickListener( new OnClickListener(){
        
        void onClick(View v){
            ....
        }
    
    });
    

    而在kotlin是使用object expression对象表达式来

    interface Test7 {}//默认是open(可实现)
    fun test(listener: Test7): Unit {
    
    }
    
    fun main(args: Array<String>) {
        
        test(object : Test7 {})//创建了一个匿名类的实例,类似于java中new 一个接口一样
    }
    

    而对于抽象类则是object : Test6(){.....},其实这个很好理解嘛...
    因为kotlin中没有new关键字,而对于抽象类和接口,我们不能像其他普通类那样创建对象,so,就要使用到object 这个关键字

    val  a = object{}//创建了一个匿名类的实例
    val b = object:Test6(),Test7{}//创建一个匿名类,这个类继承Test6和Test7
    

    数据类

    数据类的作用没啥,就是用来保存数据,就好像我们拿到服务器中的json,将它转为对象保存着(方便操作这些数据)。kotlin称这些类为数据类,用data标识

    data class Person(var name:String,var age Int){}
    

    系统会为数据类生成一下的函数

    • equals()和hashCode()
    • toString,输出格式为 Person(name="xxx",age=xx)
    • componentN() 函数群,这些函数群是为了对象解构(后面讲),N对应着属性声明的顺序,这个函数暂时不管,没涉及到,知道就好
    • copy函数

    而成为数据类需要什么要求?

    1. 主构造器至少有一个参数
    2. 主构造器的参数要用var / val 修饰
    3. 不能是抽象类和open类,也不能是sealed 类和 inner类
    4. 数据类不能继承任何类,但是可以实现接口

    对于1 2 点的主构造器先不管,下篇讲这个。而对于不能是抽象类,很好理解,就是创建数据类的时候可能不是通过正常的创建实例的方式,而不能输open类是确保这个数据类就是基类,不会导致子类对象转型问题啥的(假想..)

    总结

    1. 一般的类默认的可见度修饰符是public,而且是不可被继承的,加上open才能被继承

    2. 抽象类和接口默认是open和public的

    3. 数据有data 标识符

    4. 枚举类(enum)中的每个常量值都是该类的实例,该类不能再被实例化了

    5. sealed类算是枚举类的扩展,封闭类中的子类可以被实例化

    6. 嵌套类不能访问外部类中的成员,也就是说嵌套类中不包含有外部类的实例

    7. 内部类(inner)中可以访问外部类的成员,内部类有外部类的实例

    8. 使用object expression来创建一个匿名类的对象
      代码:

       val a = object{...}
      
    9. when相当于Java中的switch,当when作为表达式使用的时候else必须有
      代码:

       fun ty(a: Int): Int = when (a) {
           12 -> 11
           else -> 10
       }       
      
    10. 但是当when中的变量类型是enum 或者是sealed的话,可以省去else,但是把enum 或者是sealed中的常量或子类列出来

    11. -> 的用法有三

      1. when中的条件选择
      2. 函数类型 (参数类型)->返回值类型
      3. lambda表达式中 参数名称 -> 函数体
    12. 带标签的this,在inner类中使用this会有歧义,使用时需要带上标签比较好
      代码:

      class Test11 {
          val a: Int = 1
      
          inner class Nested {
              val a = 2
              fun tt(): Unit {
                  println(this@Test11.a)//访问Test11 中的a
                  println(this.a)//访问inner中的a
              }
          }
      }
      

    2017/5/30 20:47:23

    相关文章

      网友评论

        本文标题:Kotlin学习05

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