美文网首页
kotlin学习笔记二

kotlin学习笔记二

作者: wfunny | 来源:发表于2019-03-21 13:49 被阅读0次

    1.val和var声明可变和不可变变量

    val:用于声明不可变的变量,不可变指的是引用不可变,相当于Java当中的final

    var:用于声明可变的变量

    fun main(args: Array<String>) {
        val a = "a是不可变的变量" //不可变
        var another = 3 //可变
        println(a)
        println(another)
    }
    

    2.fun函数

    Kotlin中的函数可以这样声明:
    fun 函数名 (参数列表):返回值类型{函数体}
    fun 函数名 (参数列表) = 表达式

     //fun 函数名 参数列表:返回值类型{函数体} 
    fun add1(a1:Int,a2:Int):Int{
        return a1+a2
    }
    //fun 函数名 参数列表 = 表达式
    fun add2(a1:Int,a2:Int) = a1+a2
    

    还有一种比较奇怪的方式:

    fun main(args: Array<String>) {
          println(sum1(1,2))
          println(sum2(3,4))
    }
    var sum1 = fun (a1:Int,a2:Int):Int{
          return a1+a2
    }
    var sum2 = fun(a1:Int,a2:Int) = a1+a2
    

    输出:
    3
    7
    这种方式叫做匿名函数,有啥用途?目前笔者也不是很清楚,学过的大神说它相当的厉害,所以继续往后学,应该会揭晓。

    3.聪明的类型推断

    Kotlin能够很聪明的判断一些位置所应有的类型,这让程序员省心了不少。
    比如:
    以下代码:

    var a = 3 //自动推断a的类型为Int
    var str:String = "string"
    var str2 = str //自动推断str2的类型为String
    fun add(a1:Int,a2:Int) = a1 + a2 //自动推断add()方法的返回类型为a1+a2所对应的类型,也就是Int类型         
    

    4.Lambda表达式

    其实就和匿名函数一样,写法如下:
    {(参数列表) -> [函数体,最后一行是返回值]}

    fun main(args: Array<String>) {
         println(sum(1,2))
         println(sum2(3,4))
    }
    var sum = {a1:Int,a2:Int-> a1+a2 }
    var sum2 = {a1:Int,a2:Int->
                            println("$a1 + $a2 = ${a1 + a2}")
                            a1+a2
    }
    

    Lambda的类型是什么,这跟传入的类型和返回的类型相关,比如下面的代码中Lambda对应的类型如下代码所示:

     var sum = {a1:Int,a2:Int-> a1+a2 } //(Int,Int)->Int
     var str = {a1:Int,str:String->
                                 a1.toString() + str +"".toString()
                                 println(str)
               }//(Int,String)->unit
    

    Kotlinl里面的unit就相当于Java当中的void
    Lambda表达式可以嵌套使用吗?当然可以啊,比如Lambda的类型是(Int,(Int,String)->Int)->Int这不是就是Lambda表达式的嵌套吗?只不过作为初学者的我们是有点复杂哦。

    那么Lambda表达式如何调用呢?
    比如,下面Lambda表达式如何调用:
    var sum = {(a1:Int,a2:Int) -> a1+a2}

    你可以这么调用:sum(2,3)
    你也可以这么调用sum.invoke(2,3)

    5.类及类的声明

    Java当中的类的声明有以下几个方面:
    1.构造器
    2.成员变量
    3.成员方法
    4.访问权限的设置
    5.静态和非静态的设置
    6.为某些成员变量设置get和set方法
    对于那些对Java非常熟悉的同学,这些也就不需要特殊说明了把!不熟悉?那现在还不太适合学习Kotlin,理由很简单,因为面向对象思想都没有理解,那之后学习起来相当吃力的,所以,请务必先接触一下Java,再来学习Kotlin就轻松容易的多了。

    那么Kotlin如何取声明一个类呢?
    关键字还是很Java一样使用”class”关键字声明类

    5.1 构造器

    Kotlin当中的构造器的名字可不是跟Java一样,和类名相同,其构造器的名字必须是:constructor,代码如下所示:

    class Person{
        var name:String = "" //成员变量
        var age:Int = 0
        constructor(name:String,age:Int){
            this.age = age
            this.name =name
        }//Person类的构造器
    }
    

    此外Kotlin对于构造器还有一个特殊的写法,代码如下:

    class Student(var name:String,var age:Int)//构造器的特殊写法
    

    对应的代码应该是下面的样子:

    class Student{
        var name:String = "" 
        var age:Int = 0
        constructor(name:String,age:Int){
            this.age = age
            this.name =name
        }
    }
    

    此外,类的构造器分为主构造器和次构造器:

    在 Kotlin中的一个类可以有一个主构造函数和一个或多个次构造函数。主构造函数是类头的 一部分:它跟在类名(和可选的类型参数)后,如果主构造函数没有任何注解或者可见性修饰符,可以省略这个constructor 关键字。

    主构造函数不能包含任何的代码。初始化的代码可以放到以 init 关键字作为前缀的初始化 块(initializer blocks)中。

    主构造函数的参数可以在初始化块中使用。它们也可以在类体内声明的属性初始化器中使用。

    如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造 函数。构造函数的可见性是public。如果你不希望你的类有一个公有构造函数,你需要声明 一个带有非默认可见性的空的主构造函数。

    说了这么多,还不如上上代码来的直接:

    class Student(var name:String,var age:Int){//主构造函数
        init {
           name = "sda"
            age = 28
        }
        var ID:String = "20171314"
        constructor(name:String,age:Int,ID:String) : this(name,age) {
            this.ID = ID
        }//次级构造函数
    }
    

    5.2 成员变量

    这基本和Java当中是一样的,看上述代码就知道了

    5.3 成员方法

    Kotlin当中如果从属于类的函数叫做”成员方法”或者”方法”,不从属于类的叫做”函数”,什么是不从属于类呢?比如下列代码中的A()函数:

    fun main(args: Array<String>) {
        A()
    }
    fun A(){
        println("函数A()")
    }//不从属于类,是函数
    

    Kotlin中的成员方法没什么特别要说明的,基本上和Java的声明类似,代码如下:

    class Person{
        var name:String = ""
        var age:Int = 0
        constructor(name:String,age:Int){
           this.age = age
           this.name =name
        }
        fun  自我介绍(){
            println("我是$name,今年${age}岁")
        }//Person的成员方法"自我介绍()"
    }
    

    5.4 权限修饰符的设置

    Java当中的默认访问权限是default,作用于当前的包内,Kotlin的默认访问权限是public,你没看错,的确是public,kotlin的访问权限特性如下:

    类的权限修饰符:
    open:如果你确定你自定义的类是会被继承的,那么你需要给这个类添加 open 修饰符。

    final:这是kotlin默认的,也就是没有添加任何修饰符,和上面Student类一样,此修饰符代表着你的类不能被继承。

    sealed:sealed 修饰的类称为密封类,用来表示受限的类层次结构。例如当一个值为有限集中的 类型、而不能有任何其他类型时。在某种意义上,他们是枚举类的扩展:枚举类型的值集合也是受限的,但每个枚举常量只存在一个实例,而密封类的一个子类可以有可包含状态的多个实例。

    data:data 修饰的类称之为数据类。它通常用在我们写的一些 POJO 类上。
    当 data 修饰后,会自动将所有成员用operator声明,即为这些成员生成类似 Java 的 getter/setter 方法。

    成员变量修饰符:
    public:
    private:
    protected:
    上面三种我就不罗嗦了,因为和Java中的是一样的

    internal:它是模块级别的访问权限。

    何为模块(module),我们称被一起编译的一系列 Kotlin 文件为一个模块。在 IEDA 中可以很明确的看到一个 module 就是一个模块,当跨 module 的时候就无法访问另一个module 的 internal 变量或方法。这会在后面说明。

    5.5 静态和非静态的设置

    貌似Kotlin中不存在静态修饰符static,那么肯定有个替代的东西,但是存在一个伴生类的写法,它就是用来替代Java当中的静态变量和静态方法的,示例代码如下:

    fun main(args: Array<String>) {
        println(Student.a)
        println(Student.get())
    }
    class Student(var name: String,var  age: Int) {
        companion object {//静态方法和变量都应该写在这里面
            var  a:Int =  3;//静态变量
            fun get():Int{
                return a
            }
        }
    }
    

    5.6 为某些成员变量设置get和set方法

    在类前面加”data”修饰符即可达到效果,而且注意的一点就是,无论你有没有在声明类的时候加”data”关键字。

    Getters和 Setters
    声明一个属性的完整语法是

    其初始器(initializer)、getter 和 setter 都是可选的。属性类型如果可以从初始器 (或者从 其 getter 返回值,如下文所示)中推断出来,也可以省略。

    6.Kotlin对基本运算符进行重写以及创造自己的运算符

    Java当中是不能对基本的运算符进行重写的,但是Kotlin就不一样了,可以对基本运算符进行重写,怎么样,是不是感觉很牛啊!我们就拿一个数学当中的复数相加操作为例字,我们知道基本运算符中没有复数相加的操作,没关系,我们可以进行在复数类FuShu中把“+”运算符进行重写,代码如下,注意为了让童鞋们更好的理解,我使用了中文命名,实际开发中尽量少用中文:

    class 复数(var 实部:Int,var 虚部:Int){
        operator  fun plus(fuShu: 复数):复数{
            return 复数(实部 + fuShu.实部,虚部+ fuShu.虚部)
        }
        override fun toString(): String {
            return "$实部 + ${虚部}i"
        }
    }
    fun main(args: Array<String>) {
        var fuShu1 = 复数(3,4)
        var fuShu2 = 复数(4,5)
        println(fuShu1 + fuShu2)
    }
    

    输出:
    7 + 9i

    除此之外我们还可以添加我们自己的运算符,比如以下神奇的代码:

    class 人(var name:String,var age:Int){
        infix  fun 吃(str:String){
            println("我叫$name,今年${age}岁,现在正在吃$str")
        }//使用中缀表达式对自定义运算符,其实就是可以让方法可以像运算符一样被调用
    }
    
    fun main(args: Array<String>) {
       var 某个人 = 人("张三",23)
       某个人 吃 "螃蟹"
    }
    

    输出:
    我叫张三,今年23岁,现在正在吃螃蟹

    注意的是要想把方法自定义自己的运算符,此方法一定含有参数,并且只能是一个参数,要问原因,其实很简单,因为运算符只涉及两个参数,一个就是运算的,一个就是被运算的,so 明白了吧!

    7.分支表达式,when表达式…

    分支表达式?啥玩意儿?Java当中的分支语句?的确,分支表达式这很难理解,其实我把代码一贴出来,你就恍然大悟了:

    var string = readLine() //readLine()方法是接收键盘输入的字符串
     val str = if(readLine()!!.contains("1")){"11111"}else{"aaaaa"}
     //当输入的字符串当中含有子字符串"1",那么这个分支表达式就会返回字符串"11111",否则返回"aaaaa"
    

    没错,分支表达式可以具有返回值的,分支语句是不会返回值的,so 明白了吧!上述是”if表达式”是分支表达式的一种,那么肯定存在其他的分支表达式,在提到其他的分支表达式之前,必须说明一点,Java当中有个分支语句叫switch,Kotlin没有switch啦,那么咋办呢?删除switch肯定会有替代switch的啦,kotlin中的when语句就可以替代switch语句,代码如下:

    var string = readLine()
    val str = when(string){
              "1"->"11111" //当string的值为"1",注意是等于,那么就返回值"11111"
              "a"->"aaaaa"
        else->{
            "啥都不是" //当string的值不是"1"或者"a"的时候,就返回"啥都不是"
        }
    }
    

    看懂笔者写的代码,一方面你已经掌握了Kotlin分支表达式,一方面掌握了分支语句。
    区分起来很简单,一个有返回值,一个没有返回值

    8.循环语句以及关键字continue和break

    Java当中的循环语句有:for语句,while语句,那么Kotlin中的循环语句会跟Java一样 吗?

    首先,我们来看看for语句,Java当中for语句用法有:(1)集合或者数组的迭代,(2)次数循环,比如从1加到100,那么Kotlin中的for语句会是什么样子呢?

    Kotlin中的for语句:
    Kotlin中的for语句迭代很强大,比Java的还要强大,比如,有一个String[]数组,它的迭代是这样的:

    var strs:Array<String> = arrayOf("a","b","c","d","e")
    for(str in strs){
        println(str)
    }
    

    这似乎跟java的基本一样,为什么是似乎?因为Kotlin支持自动类型推断,所以在用于遍历的变量不需要指定类型,不得不再说一句自动类型推断简直太人性话了,但是有些时候,我们必须要带数组下标的方式去遍历,Java当中的for语句可就变得麻烦多了,因为必须要以下类似的写法:

     //Java当中带下标的方式去遍历String数组
     String[] strs  = {"a","b","c","d","e"}
     for(int i=0;i<strs.length;i++){
         System.ou.println(strs[i]) 
     }
    

    这简直太麻烦了,还要声明一个变量i,Kotlin可不需要,它是这样的

    var strs:Array<String> = arrayOf("a","b","c","d","e")
    //不带下标遍历数组
    for(str in strs){
        println(str)
    }
    
    //带下标遍历数组
    for((Index,Value) in strs.withIndex()){
        println("下标:$Index,值:$Value")
    } //withIndex()方法返回Iterable<IndexedValue<T>>
    

    这么一比较,又觉得kotlin那叫一个爽。那么如何使用Kotlin中的for语句求的1到100之和呢?代码如下:

    var intRange:IntRange = 1..100 // 这是[1,100]区间
    var sum = 0;
    for(i in intRange){
        sum = sum + i
    }
    println("1到100的累和结果是:$sum")
    

    接下来看看while循环,kotlin的while跟Java是一样一样的,都有
    while(条件体){循环体}

    do{循环体}while(条件体)两种方式,由于是一样的,这里我就不在啰嗦了。

    接下来,来看看kotlin中的continue和break关键字,这俩关键字也是跟Java当中是一样一样的,所以我也就再次不想啰嗦了,实例代码如下:

    fun main(args: Array<String>) {
         var students:Array<Student> = arrayOf(Student("a",1)
                                         ,Student("b",2),Studen("c",3)
                                         ,Student("d",4),Studet("e",5))
         for((Index,Value) in students.withIndex()){
               if(Value.name == "a")continue
               if(Value.name == "c")break
               println("下标:$Index,值:${Value.name}->${Value.age}")
         }
    }
    class Student(var name:String,var age:Int)
    

    9.Kotlin中的异常

    Java的异常体系是这样的:

    其中非运行时异常必须捕获和处理,通过try{}catch(){}finally{}语句来处理,除此之外,Java中可以自定义异常类,继承自基础体系中的异常,即可让自己的类加入到异常体系的大家族,具体细节,我就不罗嗦了,这都是Java的基础。

    那么Kotlin中的异常体系又是如何呢?
    Kotlin中所有异常类都是Throwable类的子孙类。每个异常都有消息、堆栈回溯信息和可选 的原因。跟Java一样代码块使用throw来抛出异常,方法使用throws来抛出异常,使用tru{}catch(){}finally{}语句来捕获和处理异常,可以有零到多个catch块。finally 块可以省略。但是catch和finally 块至少应该存在一个。这基本上和Java保持一致的,除此之外,try{}catch(){}finally{}是一个表达式,也就是说它可以具有返回值,示例代码如下:

    var str = try {
        var file = File("D:\\aa")
        var fis  = FileInputStream(file)
    }catch (e:FileNotFoundException){
        "文件木有找到"
    }finally {
        "文件找到啦"
    }
    println(str)
    

    注意的是Kotlin中并不会去取检查异常,什么意思?在Java中非运行时异常一定要捕获和处理,但是Kotlin并不存在运行时异常和非运行时异常的概念,也就是说,捕获和处理不是强制性的,这要靠程序员自己去捕获和处理,比如上面代码中的FileNotFoundException在Java当中一定是要被捕捉处理的,但是Kotlin不强制要求你捕捉和处理,为什么Kotlin要这样呢?因为强制捕捉异常会让代码变得复杂,Kotlin有其精简的特性,当然不会强制要求你捕捉异常的啦,不过,有些必须进行捕捉处理的,尽管Kotlin强制要求,我们都要去捕捉和处理。

    其实理解表达式很简单,就是表达式一定是有返回值的,这一点一定要记住,一旦理解了这一点,那么Kotlin的所有表达式,就了如指掌了。

    10.具名参数,变长参数,默认参数

    具名参数,就是通过具体的参数名来传入参数,示例代码如下:

    fun main(args: Array<String>) {
        println(add(a1 = 1,a2 = 2))//使用函数add(a1,a2)具体的参数名字"a1"(a1 = 1)和"a2"(a2 = 2)来对函数add(a1,a2)进行调用
    }
    fun add(a1:Int,a2:Int) = a1+a2
    

    变长参数,什么是变长参数呢?当你的方法不确定要传入几个参数,并且这几个参数的类型相同,那么你就可以使用变长参数的方式来满足你的要求,使用vararg关键字进行声明,示例代码如下:

    fun main(args: Array<String>) {
        println(add(1,2,3,4))
        println(add(1,3,4,0,8,2,3,5,6,7,8))
    }
    fun add(vararg ints:Int):Int{//变长的参数
        var sum = 0
        for(i in ints){
           sum = sum + i
        }
        return sum
    }
    

    我们都知道,Java中也存在这种变长参数,但是Java的变长参数只能在方法参数列表的最后面,但是Kotlin就不一样了,kotlin的变长参数可以出现在参数列表的任意位置。示例代码如下:

    fun main(args: Array<String>) {
         println(add(true,1,2,3,4,str = "哈哈哈"))
         println(add(false,3,4,0,8,2,3,5,6,7,8,str = "hello"))
         var intArray:IntArray = intArrayOf(1,2,3,4,5)
         println(add(false,*intArray,str = "sasda"))//直接把数组作为变长参数ints的值
    }
    fun add(falg:Boolean,vararg ints:Int,str:String):Int{
        var sum = 0
        for(i in ints){
            sum = sum + i
        }
        return sum
    }
    

    默认参数,在你声明自己的方法或者函数的时候,可以使用默认参数来为你的参数来个初始化,这样做的结果就是,你在调用这个方法的时候,可以不用再次传递参数给它,当然也可以传递参数给他,示例代码如下:

    fun main(args: Array<String>) {
        var r = 5.0
        println("半径为${r}cm的圆的面积为:${getYuanMianJi(r = r)}(cm*cm)")
        var r1 = 6.22
        println("半径为${r}cm的圆的面积为:${getYuanMianJi(3.1415,r1)}(cm*cm)")
    }
    fun getYuanMianJi(pi: Double = 3.14,r:Double) = r*r*pi
    

    输出结果:
    半径为5.0cm的圆的面积为:78.5(cmcm)
    半径为6.22cm的圆的面积为:121.5396086(cm
    cm)

    相关文章

      网友评论

          本文标题:kotlin学习笔记二

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