zoukankan      html  css  js  c++  java
  • Kotlin基础学习

    写在前面

    在刚开学的时候,买了一本《第一行代码Android》,但一直在上课没有机会看,这几天刚好写完了上一个项目,这段时间就对这本书进行了学习。在这本书中,由于谷歌大力推广kotlin语言,将其作为android开发的首推语言,本书也遵循了谷歌的推广,因此我就跟着书本学习了基本的Kotlin语法,当作记录笔记了。

    变量和函数

    变量

    在Koltin中的变量定义方式与java有很大不同,在kotlin中要定义一个变量,只允许在变量前声明两种关键字:val和var,val是value的简写,表示一个不可变的变量,对应java中的final关键字定义的变量。var是variable的简写,表示一个可变的变量,对应java中的非final关键字定义的变量。这时可能学过java的都会冒出一个疑惑,只靠这两个怎么能知道具体的类型呢?Kotlin里有类型推导机制,如:

      val a = 37
      println("a = " + a)
    

    这里可以看出,Kotlin不需要行尾分号了,这里我们将10赋值给了a,那么a就会被推导成整型变量。如果你把一个字符串赋值给a变量,那么a就会被自动推导为字符串变量。但需要注意的是,类型推导机制并不总是好用的,因此我们可以对一个变量进行显式声明,如:

    val a:Int = 10
    

    Kotlin里摒弃了java中的int,double,float等,全部都改用了对象数据类型,即首字母大写的类型,如Int,Double,Float。此时我们尝试对a变量进行一个扩大的操作:

    a = a * 10
    

    可以看到编译器报错了,因为val类型的变量无法被重新赋值,我们把a的类型变成var就可以了:

    var a : Int = 10
    

    函数

    首先要注意的是,方法和函数其实说的都是一个东西,只是叫法不同而已。接下来我们看看如何在kotlin中定义一个函数:

    fun largerNumber(num1:Int,num2:Int):Int{
        return max(num1,num2)
    }
    

    fun表示function,即声明函数,后面就是函数名了。函数名后的括号里为变量参数列表,参数的声明格式为:"参数名:参数类型"。参数后面的冒号内容可以省略,表示返回值类型,这里我们声明为返回一个Int型的数据。这里使用了一个max函数,表示取二者的最大值。

    这里我们提一句语法糖,当返回值只有一句代码时候,我们可以将大括号省略,用等号连接,且return也可以省略。如下:

    fun largerNumber(num1:Int,num2:Int):Int = max(num1,num2)
    

    而我们刚才提到了kotlin的类型推导机制,返回值肯定是一个Int值,因此我们不需要显式声明返回值类型了。就可以写成:

    fun largerNumber(num1:Int,num2:Int) = max(num1,num2)
    

    逻辑控制

    if条件语句

    Kotlin的if和java几乎没有任何区别,但需要注意的是,kotlin中的if条件语句是有返回值的,返回值为if语句每个条件中的最后一行代码的返回值。意味着我们可以这么写:

    fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
    

    这里又使用了上面提到的语法糖,因为这里放到大括号里也就是return 一句话,所以符合语法糖的规则。

    when条件语句

    kotlin中的when有点像java中的switch,但比起switch要强大的多。switch里面只能传入整型和短于整型的变量作为条件,JDK1.7后还引入了字符串变量的支持。但如果我们传入的类型不是这些,那么switch语句就无法使用了。同时,switch语句的最后需要加一个break,否则会顺序执行每个case。而kotlin不仅解决了以上的痛点,还添加了很多好用的功能。

    比如我们先看一个简单的通过姓名输出学生分数的功能:

    fun getScore(name:String) = if(name =="Tom"){
        86
    }else if(name == "Jim"){
        77
    }else if(name == "Jack"){
        95
    }else if(name == "Lily"){
        100
    }else{
        0
    }
    

    这里又再次使用了单行代码函数的语法糖,但写了这么多if和else显得代码十分冗余,这里我们改用when的写法:

    fun getScore(name: String) = when (name) {
        "Tom" -> 86
        "Jim" -> 77
        "Jack" -> 95
        "Lily" -> 100
        else -> 0
    }
    

    when语句可以传入一个任意类型的变量,然后在when的结构体定义一系列的条件,格式为: 匹配值 -> {执行逻辑},当执行逻辑只有一行的时候,大括号就可以省略了。

    除了精确匹配外,when还支持类型匹配,比如我们定义一个checkNumber()函数:

    // when类型匹配
    fun checkNumber(num: Number) {
        when (num) {
            is Int -> println("number is Int")
            is Double -> println("number is Double")
            else -> println("number not support")
        }
    }
    

    在上面的代码中,is相当于java中的instance of,而Number是kotlin中的一个抽象类,像Int,Float,Double等与数字有关的类都是他的子类,我们可以通过类型匹配来判断是什么类型。比如:

    val num = 10.0
    checkNumber(num)
    

    就会输出Double类型了。

    需要注意的是,kotlin中判断字符串或者对象是否相等用 == 就可以了,不再需要调用equals方法。

    循环语句

    kotlin中有两种循环,while和for循环,而while循环和java基本一模一样,因此不再提了,而java中常用的for-i循环被kotlin舍弃,java中的另一种for-each循环则被大幅加强,变成了for-in循环。在学习循环前,要先学习区间的概念,这也是java种没有的。如下代码:

    val range = 0..10
    

    这段代码的意思其实就是[0,10]的意思,有了区间,我们就可以用for-in来遍历区间了:

     for (i in range){
         println(i)
    }
    

    但很多时候,我们一般不会用左右闭区间,而会使用左闭右开区间,kotlin也提供了until关键字来实现这个功能:

      for (i in 0 until 10){
        println(i)
      }
    

    这时生成的就是[0,10)区间了。

    默认情况下,会在区间范围内递增1,我们可以用step来递增更多,如:

    for(i in 0 until 10 step 2){
        println(i)
    }
    

    这时就是递增2了,相当于i+=2的意思。

    但需要注意的是,..和until都只能左边小右边大,也就是只能创建升序区间,而创建降序区间可以用downTo,如:

    for (i in 10 downTo 1){
    	println(i)
    }
    

    downTo也可以使用step,不再多提了。

    类与对象

    基本用法

    在面向对象语言中,类和对象是很重要的概念。kotlin自然也有这样的概念。

    我们先来通过IDE来定义一个类:

    class Person() {
    }
    

    可以看到,kotlin也是使用class关键字来声明类的,这点与java一致。我们定义几个变量和函数:

    class Person() {
        var name = ""
        var age = 0
        fun eat(){
            println(name + " is eating.He is " + age + " years old")
        }
    }
    

    这里用var是因为我们要在创建对象后对其进行重新赋值,eat函数就不再解释了,很简单。

    接下来我们把这个类实例化一下:

    val p = Person()
    p.name = "Jack"
    p.age = 19
    p.eat()
    

    可以看到,与java不同的是,我们不再需要new关键字了,因为你调用一个类的构造方法只可能是为了对类进行实例化。接下来我们执行这段代码,发现结果和我们想的一致。

    继承与构造函数

    面向对象的一个重要特性就是继承,我们先定义一个Student类:

    class Student {
    }
    

    要让Student类继承Person类,我们要干两件事:

    1. 使Person类可以被继承。这话听起来似乎很怪,java中所有类默认都是可以被继承的,但Kotlin却不是,在Kotlin中任何一个非抽象类默认都是不可以被继承的,而抽象类如果不继承就无任何意义,所以必须被继承。想要让一个类可以被继承,其实很简单,加上一个open关键字就可以了:

      open class Person() {
          var name = ""
          var age = 0
          fun eat(){
              println(name + " is eating.He is " + age + " years old")
          }
      }
      
    2. 第二件事,自然就是让Student类继承Person类了,如下写法:

      class Student:Person(){
          var sno = ""
          var grade = 0
      }
      

      继承的写法首先,不再需要extends关键字,加上冒号即可。之后如果仔细观察,会发现多了一对括号。而要理解括号,就要解释另一个概念——构造函数了。

    在Kotlin中,有两类构造函数,主构造函数与次构造函数,主构造函数只能有一个,且没有函数体。直接定义在类名的后面。而次构造函数则是可以有任意多个,且有函数体。如下例子:

    class Student(var sno:String,var grade:Int) 
    

    这种就是典型的主构造函数定义了。如果我们要在主构造函数里写一些逻辑,就需要用到init结构体了:

    init{
        println("sno is " + name)
        println("grade is " + age)
    }
    

    而根据继承的特性,子类的构造函数必须调用父类的构造函数。这时我们要怎么调用父类的主构造函数呢?自然是在继承上写了:

    因此,如果我们再看上面的最开始的定义就会更加明了了。其实就是调用了父类的无参构造方法,就算是无参的也不能省略括号。如果我们对Person函数改造一下,将Person函数改成有参的构造方法:

    open class Person(val name:String,val age:Int) {
    }
    

    此时的Student类要继承Person类,就必须实现他的主构造函数,即必须传入name和age两个值。我们的Student类就可以写成这样:

    class Student(val sno:String,val grade :Int, name: String , age :Int):Person(name,age){
    }
    

    这里定义name和age时不能再声明成val,因为在主构造函数中声明的参数都会默认变成该类的字段。这会导致与同名的name和age发生冲突。因此不用再加任何关键字。

    至于次构造函数,当一个类有主构造函数和次构造函数时,所有的次构造函数必须调用主构造函数。具体的例子就不再写了。

    接下来我们看一个特殊情况,当一个类没有显式定义主构造函数而且定义了次构造函数时,它就是没有主构造函数的。此时继承Person类就不再需要加上括号了,因为没有主构造函数。

    接口

    kotlin是继承自java的语言,自然很多方面都很像了。在接口方面,与java有很多相似。我们先定义一个接口:

    interface Study {
        fun readBooks()
        fun doHomework(){
            println("do homework default")
    
        }
    }
    

    这里kotlin和java一样,支持为接口定义默认函数体,使得实现类不需要实现这个方法。我们让Student类实现这个接口:

    class Student( name:String, age:Int) :Person(name,age),Study {
        override fun readBooks() {
            println(name + "is reading")
        }
    }
    

    这里可以看到,kotlin中接口的关键字也是冒号,且只需要复写方法即可。我们在main函数调用该方法即可。

    这里还需要提一下,函数的可见性修饰符。见下表:

    修饰符 Java Kotlin
    public 所有类可见 所有类可见(默认)
    private 当前类可见 当前类可见
    protected 当前类、子类、同一包路径下的类可见 当前类、子类可见
    default 同意包的路径下的类可见(默认)
    internal 同一模块中的类可见

    这里的模块概念暂时不深究。

    数据类与单例类

    在写web时候,model是很常用的一种类。我们在kotlin中如何定义一个数据类呢?如下:

    data class CellPhone(val brand:String,val price:Double)
    

    只需要加上data关键字,所有需要的方法就全部都实现了,如toString(),equals等等方法。

    关于单例模式,也是我们很常见的一种设计模式。要使用单例类,如下:

    object Singleton {
        fun singletonTest(){
            println("singletonTest is called")
        }
    }
    

    只需要定义为object类即可。要调用里面的方法,如下:

     Singleton.singletonTest()
    

    即可。这样看上去是静态方法的调用,但其实kotlin在背后为我们自动创建了一个Singleton类的实例,并保证全局只会存在一个Singleton实例。

    总结

    这些只是最基本的知识,kotlin中更重要的特性例如Lambda编程,空指针检查机制等等就不再这里提了,以我的水平无法总结的很好。日后学习的多了之后再加深吧。

  • 相关阅读:
    TextView 字数限制
    关于一个软件ipa包的其他图片资源
    查看一个软件ipa包的内容
    不断学习的博客
    高级iOS面试题
    CocoaPod出现-bash: pod: command not found 解决办法
    链表清空
    蛋疼的并查集
    再卖菜
    乒乓球男双输了
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/13435731.html
Copyright © 2011-2022 走看看