Kotlin的基础

前言:

Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,被称之为 Android 世界的Swift,由 JetBrains 设计开发并开源。Kotlin 可以编译成Java字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。

现在国外很多源码都采用了Kotlin语言,替代Java只是时间问题.
通俗来说,JetBrains是Kotlin的亲爹,Google是Kotlin的干爹.

Kotlin的学习网站
中文网站 https://developer.android.google.cn/kotlin/add-kotlin
觉得英文不错的可以看 https://kotlinlang.org

下面从简到难,带你进入Kotlin的世界,

  • 基础语法
  • 比较与数组
  • 条件控制
  • 循环与标签
  • 类与对象

基础语法

变量

可变变量定义:var 关键字

格式:var<标识符> : <类型> = <初始值>

不可变变量定义:val 关键字

格式:val<标识符> : <类型> = <初始值>

image.png

通过AndroidStudio的Tools - Kotlin - Show Kotlin Bytecode可以看出var是一个普通的变量,而val是final修饰的常量,而且var修饰的变量有get和set方法,val修饰的变量只有get方法. 如下图
image.png
类型推断

在Kotlin中变量的类型是省略的.如图
image.png

在前面有提到Kotlin是静态语言,变量在编译期就确定了类型, 跟JS动态语言不同.

函数

普通函数定义:fun关键字

格式: fun <函数名>(var/val<标识符> : <类型>,...,var/val<标识符> : <类型> ):<返回类型>{
}

fun main() {
    add(1,2)
}

fun add(number1:Int,number2:Int) : Int{
     return number1 + number2
}

无返回值的函数,关键字Unit 通常可以省略

fun main() {
    add(1,2)
}

fun add(number1:Int,number2:Int) : Unit{

 }

函数返回值为类型推断函数

fun main() {
   add(1,2)
}

fun add(number1:Int,number2:Int) = number1 + number2 //类型推断返回值为Int

可变参数函数

fun main() {

    add(1,2)

}
//vararg 可变参数的关键字
fun add(vararg values:Int){
    for (value in values) {
        println(value)
    }
}

lambda表达式函数

fun main() {
    val sum = add(1,2)
    println(sum)
}
//lambda表达式函数
val add:(Int,Int) -> Int = {number1,number2 -> number1 + number2 }
fun main() {
    //lambda表达式函数
    val add:(Int,Int) -> Int = {number1,number2 -> number1 + number2 }

    val sum = add(1,2)
    println(sum)
}

字符串模板
fun main() {
    val name = "Zyang"
    val age = 28
    val info = "abcdefg"

    println("name:$name ,age:$age,info:$info")
}

image.png

多行输出
带有前置空格

fun main() {
    println("---------------------")
    val infoMessage = """
       AAAAAAA
       BBBBBBB
       CCCCCCC
       DDDDDDD
       EEEEEEE
       FFFFFFF
    """ // 带有前置空格
    println(infoMessage)
}
image.png

去掉前置空格

fun main() {
    println("---------------------")
    val infoMessage = """
       AAAAAAA
       BBBBBBB
       CCCCCCC
       DDDDDDD
       EEEEEEE
       FFFFFFF
    """.trimIndent() // 去掉前置空格
    println(infoMessage)
    println("---------------------")
}
image.png

去掉字符

fun main() {
    println("---------------------")
    val infoMessage = """
       ~AAAAAAA
       ~BBBBBBB
       ~CCCCCCC
       ~DDDDDDD
       ~EEEEEEE
       ~FFFFFFF
    """.trimMargin("~") // 去掉前置空格
    println(infoMessage)
    println("---------------------")
}
image.png

显示特殊字符 $999.99

fun main() {
    val price = """
        ${'$'}999.99
    """.trimIndent()
    println(price)
}
image.png
NULL检查机制 '?'

Kotlin的空安全设计对于声明可为空的参数,在使用时进行空判断处理.
image.png

通常有两种null判断处理方式, 字段后加!! 和 另一种是字段后加?

fun main() {
   var info:String? = null

    println("第一种:${info?.length}")//如果info是null, 就不执行.length

    println("第二种:${info!!.length}") // !! 我自己担保info 不为null,执行到此处,如果info为null 就会抛出空指针异常
  
    if(info != null){
      println(info.length) //第三种补救措施, 跟java 一样
    }
}
image.png

在函数返回值中, 如果返回值返回的是null,必须在返回类型上面做有null返回的标识?

image.png

在使用这个函数的时候, 必须要做null补救措施.


image.png
区间 'in'
fun main() {
    //默认是从小到大
    for (i in 1..9){
       println("从小到大:$i")
    }
    println("---------------------")
    //从大到小
    for (i in 9 downTo 1){
        println("从大到小:$i")
    }
    //指定步长
    for (i in 1 ..10 step 2){
        println("指定步长:$i")
    }
    println("---------------------")
    //排除最后的元素
    for (i in 1 until 10){
        println("排除最后元素:$i")
    }
    println("---------------------")
    //通过in 去做if判断
    val value = 99
    if (value in 1..100){
        println("包含在1到100之间")
    }
    println("---------------------")

}

执行结果
image.png

比较与数组

比较两个值
fun main() {
    val name1 = 1110
    val name2 = 1110

//  比较值的本身, == 相当于 Java的equals, 在Kotlin中不建议使用equals, 直接用== 来代替
    println("比较值的本身------")
    println(name1.equals(name2))
    println(name1 == name2)


//   比较对象的地址
    println("比较对象内存地址------")
    val test1:Int? = 1110
    val test2:Int? = 1110
    println(test1 === test2)

}

执行结果
image.png
数组

第一种方式,开发中常用的方式

fun main() {
    val numbers = arrayOf(1,2,3,4,5,6,7,8,9)

    println("第一个元素:${numbers[0]}")
    println("------------------------")
    for (number in numbers) {
        println(number)
    }
}
image.png

第二种方式
在100的基础上面, 向后面加10次的1

fun main() {
    val numbers  = Array(10,{value:Int->(value + 100)})

    for (number in numbers) {
        println(number)
    }
}
image.png

条件与控制

if

区间判断

fun main() {
    val x = 80
    val y = 20

    if (x in 1..10 && y in 1..50){
        println("x,y 符合")
    }else{
        println("x,y 不符合")
    }

}

表达式比较 大小, 并返回最大值

fun main() {
    val number1 = 10;

    val number2 = 20 ;

    val maxValue = if (number1 > number2) number1 else number2

    println(maxValue)

}

表达式比较 大小, 经过逻辑处理, 并返回最大值

fun main() {
    val number1 = 10;

    val number2 = 20 ;

    val maxValue = if (number1 > number2){
        println("自己逻辑处理的代码")
        number1 //必须要有返回值, 跟函数不一样, 不需要用return
    }else{
        println("自己逻辑处理的代码")
        number2 //必须要有返回值, 跟函数不一样, 不需要用return
    }

    println(maxValue)

}
when相当于java中的switch
fun main() {
    val number1 = 5

    when(number1){
        1 -> println("一")
        2 -> println("二")
        3 -> println("三")
        4 -> println("四")
        5 -> println("五")
        else -> println("其他")
    }

    val number2 = 745

    when(number2){
        in 1..100 -> println("1...100")
        in 100..1000 -> println("1...1000")
        else -> println("其他")
    }
}

另外一种方式

fun main() {
    val number1 = 2

    val result =  when(number1){ //类型推断为String
        1 -> {
            println("今天星期一")
            "今天星期一" //这是返回值
        }
        2 -> {
            println("今天星期二")
            "今天星期二"//这是返回值
        }
        3 ->{
            println("今天星期三")
            "今天星期三"//这是返回值
        }
        else -> "其他"//这是返回值
    }
     println("今天星期三")
}

标签与循环

标签
自定义标签,跟Java的goto一样

fun main() {
    ttt@ for (i in 1..20){
        for (j in 1..20){
            if (i == 5){
                break@ttt
            }
        }
    }
}

类自带的标签

class Zyang {
    val name = "yang"

    fun show(){
        println(name)
        println(this.name)
        println(this@Zyang.name) //这是类自带的标签
    }
}

循环

 val items = listOf<String>("张三", "李四", "王五")

    //循环遍历
    for (item in items) {
        println(item)
    }

    items.forEach { item->
        println(item)
    }

    //获取下标,并打印下标的值,  index 是下标
    for (index in items.indices) {
        println("下标:$index ,对应的值:${items[index]}")

类与对象

空类

//这是一个空类, 默认就是public, final 
class Empty

类的构造
主构造

class Person(id:Int) { //(id:Int) 是主构造

}

次构造
次构造里面必须要先引入主构造 ':this(id)'

class Person(id:Int) { //(id:Int) 是主构造
    //这是次构造
    constructor(id:Int,name:String):this(id){

    }
    //次构造, 构造函数重载
    constructor():this(298){

    }
}
fun main() {
    val person = Person()  //这是先调用次构造, 然后调用主构造
   
    val person1 = Person(123) // 这是直接调用主构造

    val person2 = Person(123,"张三") // 次构造
}

继承
在Kotlin 里面默认是不能继承的, 因为类默认是final. 如果想要能被继承必须要加open.

父类
open class Person(id:Int) { //(id:Int) 是主构造
    //这是次构造
    constructor(id:Int,name:String):this(id){

    }
    //次构造, 构造函数重载
    constructor():this(298){

    }
}
子类
class Student(id:Int) :Person(id) { //把子类的主构造id 穿给父类的主构造
}

在Kotlin中, 所有的变量都是没有默认值的,在Java中类的类的成员都是有默认值的,但是在方法内部是没有默认值
image.png

必须要给类成员变量赋值,如果你要给类的成员赋值为null , 必须要给他声明?

image.png

image.png

但是在使用变量的时候, 会照成一些麻烦,这时候我们可以使用变量的懒加载,注意,懒加载的变量是不能用val 去修饰的.
懒加载变量如果没有赋值, 就不能使用, 如果使用就会抛出异常
image.png

抽象类与接口

Kotlin 的类,默认都是public final, 但是在接口 和抽象类中,都默认把open打开了.
接口

//接口默认就是open
interface Callback {

    fun callbackMethod():Boolean
}

实现接口

class CallbackImpl:Callback {
    override fun callbackMethod(): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}

抽象类

abstract class AbstractCallback:Callback {

    abstract fun getLayoutId():Int

    abstract fun initView()

}

继承抽象类
在类中都是有默认的主构造,就跟Java中类中都有默认的无参构造一样. 在继承类的时候 , 必须要处理父类的主构造

  class CallbackImpl:AbstractCallback() { //() 这是处理父类的主构造
    override fun initView() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun getLayoutId(): Int {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun callbackMethod(): Boolean {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }
}  

最终可以写成这样

class CallbackImpl:AbstractCallback() { //() 这是处理父类的主构造
    override fun initView() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }

    override fun getLayoutId(): Int =  R.layout.main_activity

    override fun callbackMethod(): Boolean = false
}

data数据类
data 类, 相当于java中的实体Bean 在java Bean 里面有get set方法, 但是在kotlin中没有get,set. data 它帮我们自动生成一个Java Bean

data class User (val id:Int,val name:String, val sex:Char)

通过AndroidStudio的Tools - Kotlin - Show Kotlin Bytecode 看到生成的java源码

public final class User {
   private final int id;
   @NotNull
   private final String name;
   private final char sex;

   public final int getId() {
      return this.id;
   }

   @NotNull
   public final String getName() {
      return this.name;
   }

   public final char getSex() {
      return this.sex;
   }

   public User(int id, @NotNull String name, char sex) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      super();
      this.id = id;
      this.name = name;
      this.sex = sex;
   }

   public final int component1() {
      return this.id;
   }

   @NotNull
   public final String component2() {
      return this.name;
   }

   public final char component3() {
      return this.sex;
   }

   @NotNull
   public final User copy(int id, @NotNull String name, char sex) {
      Intrinsics.checkParameterIsNotNull(name, "name");
      return new User(id, name, sex);
   }

   // $FF: synthetic method
   @NotNull
   public static User copy$default(User var0, int var1, String var2, char var3, int var4, Object var5) {
      if ((var4 & 1) != 0) {
         var1 = var0.id;
      }

      if ((var4 & 2) != 0) {
         var2 = var0.name;
      }

      if ((var4 & 4) != 0) {
         var3 = var0.sex;
      }

      return var0.copy(var1, var2, var3);
   }

   @NotNull
   public String toString() {
      return "User(id=" + this.id + ", name=" + this.name + ", sex=" + this.sex + ")";
   }

   public int hashCode() {
      int var10000 = this.id * 31;
      String var10001 = this.name;
      return (var10000 + (var10001 != null ? var10001.hashCode() : 0)) * 31 + this.sex;
   }

   public boolean equals(@Nullable Object var1) {
      if (this != var1) {
         if (var1 instanceof User) {
            User var2 = (User)var1;
            if (this.id == var2.id && Intrinsics.areEqual(this.name, var2.name) && this.sex == var2.sex) {
               return true;
            }
         }

         return false;
      } else {
         return true;
      }
   }
}

data数据类的使用

fun main() {
    val user = User(99,"李思思",'M')

    val(myId,myName,mySex) = user.copy() //通过copy 拷贝一份对象

    println("myId:$myId,  myName:$myName,  mySex:$mySex")

    val(_,myName2,_) = user.copy() //通过copy 拷贝一份对象, _ 不接受这个参数
    println(" myName2:$myName")

}

object单例类

//只实例一次 , 相当于单例
object ObjectDemo {
    fun funM(){
        println("fuM")
    }
}


fun main() {
    ObjectDemo.funM()
    ObjectDemo.funM()
    ObjectDemo.funM()
    ObjectDemo.funM()
    ObjectDemo.funM()
}
Kotlin内部类 inner
class ClassDemo {

    val I = "AAAA"

    //这个不是一个内部类,这只是嵌套类, 所以拿不到外部成员
    class Sub{

        fun show(){
            println(I) //编译报错, 拿不到 I 这个值
        }
    }


    //真正的内部类
    inner class Sub2{

        fun show(){
            println(I)
        }
    }

}
Kotlin单例模式

companion object 派生,随着类的加载而存在,相当于Java中类中的static

image.png

单例模式1,Kotlin版

class NetManager {

    //派生操作
    companion object{
        //全部相当于java中的static
        fun getInstance():NetManager = Holder.instance

    }

    object Holder{
        val instance = NetManager()
    }


    fun show(name:String){
        println("show:$name")
    }

}


fun main() {
    val net = NetManager.getInstance()
    net.show("kt Zyang")
}

单例模式2,Kotlin版

class NetManager {

    //派生操作
    companion object{
        private var instance:NetManager? = null

        fun getInstance():NetManager{
            if (instance == null){
                instance = NetManager()
            }
            return instance!!
        }
    }

    fun show(name:String){
        println("show:$name")
    }

}


fun main() {
    val net = NetManager.getInstance()
    net.show("kt,Zyang")
}

Kotlin 关于高阶函数,与协程 属于Kotlin进阶内容, 在后面会有专门的文章去介绍这部分内容.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350