美文网首页
Kotlin学习笔记(二)-程序结构(上 )

Kotlin学习笔记(二)-程序结构(上 )

作者: g小志 | 来源:发表于2019-12-13 15:01 被阅读0次

    [TOC]

    前言

    上节我们主要讲了Kotlin的数据类型,这节我们主要从程序结构,包括方法,类成员,运算符的角度去认识Kotlin

    常量与变量

    上一节我们已经用到了用val,var来修饰属性。这节我们详细总结下:

    • 常量(val)
      • val=value,值类型
      • 类似Java的final
      • 不可能重复赋值
      • 运行时常量: val x = getX()
      • 编译期常量: const val x=2

    Java final是运行时常量 Kotlin是编译器常量 例子:

    Java:
    
    public final String S1="A"
    public String s2=S1
    
    运行时字节码: 
    public s2="A" //直接指向值 而不是变量名  
    
    Kotlin:
    
    val S1:String="A"
    var s2:String =S1
    
    运行时字节码: 
    static{
        s2=S1//这里没有直接指向S1的值 所以是编译期常量
    }
    
    • 变量(var)

      • var = variable
      • var x ="HelloWorld"//定义变量
      • x ="HiWorl"//再次赋值
    • 类型推导
      编译器可以推导量的类型

      • val string =“Hello"//推导出String类型
      • valint=5IIInt类型
      • var x = getString() + 5 //String类型
    函数

    函数是以特定功能组织起来的代码块

    举例:

    • fun sayHi(name: String){ println("Hi, $name") }
    • fun sayHi(name: String) = println(“Hi, $name")
    • 匿名函数
      • fun([参数列表])): [返回值类型]{ [函数体] }
        • 举例:- val sayHi = fun(name: String) = println(“Hi, $name")

    Java是面向对象的,Kotlin是面向函数的,函数是一等公民,是在Java中你可以将调用一个对象,也可以将一个对象传来传去,在Kotlin中函数也是可以的做到像Java对象一样,下面结合代码来体验一下

    fun main(args: Array<String>) {
        
        //不建议这么去写  这么写 是无法区分你想调用的是常量还是函数
        //这里和重载也不相同 因为val sum =fun 后面接的是无方法名的方法
        //这里默认是调用的方法  如果想调用常量方法  可以使用sum.invoke()等价于 sum()
        println("方法函数 " + sum(args[0].toInt(), args[1].toInt()))
        println("方法函数 invoke: " + sum(args[0].toInt(), args[1].toInt()))
        println("常量" + sum.invoke(args[0].toInt(), args[1].toInt()))
    
    }
    fun sum(aInt1: Int, aInt2: Int): Int {
        return aInt1 + aInt2
    }
    
    val sum = fun(aInt1: Int, aInt2: Int): Int {
        println("$aInt1 + $aInt2 = ${sum(aInt1, aInt2)}")
        return aInt1 + aInt2
    }
    fun printlnUarge(): String {
        return "请输入两个数值 例: 1 2"
    }
    
    val uager = fun(): String {
        return "请输入两个数值 例: 1 2"
    }
    
    Lambda表达式

    Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
    使用 Lambda 表达式可以使代码变的更加简洁紧凑。
    Java1.8加入,Kotlin作为面向函数编程的语言,他一出生就完美支持lambda

    • 语法
    (parameters) -> expression
    或
    (parameters) ->{ statements; }
    
    
    • lambda表达式的重要特征

      • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
      • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
      • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
      • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

    简单例子:

    // 1. 不需要参数,返回值为 5  
    () -> 5  
      
    // 2. 接收一个参数(数字类型),返回其2倍的值  
    x -> 2 * x  
      
    // 3. 接受2个参数(数字),并返回他们的差值  
    (x, y) -> x – y  
      
    // 4. 接收2个int型整数,返回他们的和  
    (int x, int y) -> x + y  
      
    // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void在Kotlin中时Unit)  
    (String s) -> System.out.print(s)
    

    Lambda表达式要是细说的话可能一篇文章也不够,我觉得刚开始看虽然代码变的更简洁,但是对我我这种只会Java一种语言的来说一下子转变有时候还是挺别扭的,感觉这个就得多写多看慢慢适应。

    这里我再结合前面讲的函数和Kotlin特性写几个例子:

    fun multiply_1(arg1: Int, arg2: Int): Int {//具名函数 Lambda: (Int,Int)->Int
        return arg1 * arg2
    }
    
    fun multiply_2(arg1: Int, arg2: Int) = arg1 * arg2//具名函数 Lambda: (Int,Int)->Int
    
    val multiply_3 = { arg1: Int, arg2: Int -> arg1 * arg2 }//匿名函数 Lambda: (Int,Int)->Int
    
    
    val multiply_4 = { arg1: Int, arg2: Int ->
        //lambda
        println("HelloWorld multiply_4")
        println("HelloWorld multiply_4")
        println("HelloWorld multiply_4")
        arg1 * arg2//最后一行作为lambda的返回值
    
    }
    val multiply_5 = fun(arg1: Int, arg2: Int): Int {
        return arg1 * arg2
    }//匿名函数 Lambda: (Int,Int)->Int
    val multiply_6 = {//匿名函数 Lambda: ()->Unit
        //lambda
        println("HelloWorld")
    }
    
    fun printlnUsage() {//具名函数 Lambda: ()->Unit
        println("no return element")
    }
    //匿名函数 Lambda: ()->Unit
    val sum1 = { it: String ->
        println(it)//方法体内容
        Unit//最后一行作为lambda的返回值 Kotlin Unit相当于Java的Void无返回值
    }
    
    

    这几个例子应该覆盖了我们会用到的大部分例子的类比了。

    • 循环语句
      Kotlin的循环语句有些特殊看下面的例子:
    //args=a b c d e f
    fun main(args: Array<String>) {
    
        for (i in args) {
            println(i)
        }
        args.forEach{
            if (it == "d") return
            println(it)
        }
        println("The End")
    }
    

    当调用第二种循环,如果如上想跳出循环,那么println("The End")这句并不会执行。因为 {}中的内容是表达式而不是函数,所以return的是main这个函数,可以改成如下:

        run Break@/*外部标识*/{
            args.forEach Continue@/*内部标识*/{
                if (it == "d") return@Continue
                println(it)
            }
    
        }
        println("The End")
    

    添加标识,return@Continue相当于java的Continuereturn@Break相当于Java的break。(这里标识的定义是随便写的,@A @ABC都可以)

    成员方法和成员变量

    这部分比较简单直接举例子:

    class X
    class B {
    //    lateinit var a:Int //错误 不能再原始类型中使用 lateinit
    //    lateinit var a:Double//error
    //    lateinit var a1:Long//error
    //    lateinit var a2:Float//error
    //    lateinit var a3:Short//error
    //    lateinit var a4:Char//error
    //    lateinit var a5:Byte//error
    //    lateinit var b: Boolean//error
        var a: Int = 0
            get() = field//默认可以不写
            set(value) {//默认可以不写
                field = value
            }
        lateinit var c: String
    
        lateinit var x1: X
        //    lateinit  val x2: //错误  不可以 val 类似final 定义后别虚初始化
        val x2: X by lazy {
            X()
        }
        var cc: String? = null
    
        fun value() {
    
        }
    }
    
    fun main(args: Array<String>) {
    
        val b = B()
        b.value()
        b.a
    }
    

    我们直接对上面的代码进行总结:

    • var/val a: Int = 0默认访问修饰符是public,同时默认帮我们getter和setter,当然我们也可以重写这两个方法
    • field这个属性(也叫Backing Field)只能在getter和setter才能访问到,更多详见理解Backing Field
    • Kotlin建议val/var修饰的属性最好直接初始化或是在构造方法中初始化,如果不可以就降级为局部变量**
    • lateinit延时初始化,不可以修饰val不可以修饰基本数据类型(因为基本数据类型有默认值),理智使用lateinit否则会空指针
    • by lazy{} 可以修饰val

    结语

    篇幅不宜过长,下篇继续说说程序结构

    Github源码直接运行,包含全部详细笔记

    相关文章

      网友评论

          本文标题:Kotlin学习笔记(二)-程序结构(上 )

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