Kotlin

第一章(入门)

基础
  1. var 可变变量 val 不可变变量

  2. 可以不用指定类型,会自动推导 eg:

    1
    2
    3
    var v1: Int = 10
    var v2 = 11
    val v3 = 12
  3. String 跟 String?是两种不同的类型,String 类型不能为空,String?可以空

  4. 强转符号 !! eg:

    1
    2
    3
    4
    5
    6
    7
    8
    var s1: String = "123"
    var s2: String? = null

    fun main(args: Array<String>) {
    //需要强转
    s1 = s2!!
    s2 = s1
    }
  5. 函数声明 fun xxx(param: type): returnType{ … } eg:

    1
    2
    3
    4
    fun printlen(str: String): String {
    println("stringValue: $str")
    return str
    }
  6. kotlin中if else 是一个表达式(有返回值),不是语句

    1
    2
    3
    fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
    }
  7. kotlin中赋值是语句,不是表达式

  8. 字符串模版 ->占位符$

    1
    2
    3
    4
    5
    //case 1
    val str = "kotlin"
    println("hello,$str")
    //case 2 :表达式
    println("hello,${if(str=="kotlin") "kotlin" else "java"}")
  9. 类定义

    1. Java vs kotlin

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Person {
      private String name;

      public Person(String name) {
      this.name = name;
      }

      public String getName() {
      return name;
      }
      }

      转成kotlin: 值对象->只包含数据,不包含对数据的操作

      1
      class Person(val name: String)
    2. 类属性:

      • 声明了属性,就隐式声明了该属性的get跟set
      • 如果是val属性,那么只有get
      • 如果是is开头的属性,get方法也是is开头的
    3. 自定义类属性的get跟set方法:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      class Rectangle(val height: Int, val width: Int) {
      //方式1
      val isSquare: Boolean
      get() {
      return height == width
      }
      //方式2
      val isRect: Boolean
      get() = height > 0 && width > 0
      }

      fun main(args: Array<String>) {
      val rectangle = Rectangle(10, 10)
      println(rectangle.isRect)
      println(rectangle.isSquare)
      }
  10. 包结构

    1. kotlin中可以将多个类,多个方法放在一个kt文件中
    2. 不同包下使用类的时候跟java一致,不同的是kotlin可以导入方法
  11. 枚举

    java使用enum关键字即可,kotlin需要使用enum class

    1. java

      1
      2
      3
      public enum Gender {
      Man, Woman
      }
    2. kotlin

      1
      2
      3
      enum class Gender {
      Man, Woman
      }
  12. when

    1. When 替代switch case;when跟if else一样是个表达式,不是语句

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      enum class Gender {
      Man, Woman
      }

      fun getGender(gender: Gender): String {
      return when (gender) {
      Gender.Man -> "男"
      Gender.Woman -> "女"
      }
      }

      fun main(args: Array<String>) {
      val gender = getGender(Gender.Man)
      println("性别:$gender")
      }
    2. 组合的情况,用逗号隔开

    3. when允许任何对象作为分支条件

    4. when可以不指定参数,分支条件可以为任意的boolean表达式

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      fun getLevel(score: Int)  =
      when {
      (score in 0..59) -> "不及格"
      (score in 60..100) -> "及格"
      else -> throw Exception("分数不正确")
      }

      fun main(args: Array<String>) {
      println(getLevel(10))
      }
  13. 类的智能转换:java中做类型转换前会使用instanceOf() 方法判断,之后再进行强转,kotlin中使用(a is b)进行判断,并且判断之后a对象自动转换为b类型,不需要强转

  14. while 跟java完全一致

  15. forin替代java中的for循环

    1. 整数遍历

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      for (i in 1..10) {
      println(i)
      }

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

      for (i in 1..10 step 2) {
      println(i)
      }
      //不包括11
      for (i in 1 until 11) {
      println(i)
      }
    2. 遍历数组

      1
      2
      3
      4
      val arrayList = arrayListOf<String>("1", "2")
      for ((index,item) in arrayList.withIndex()){
      println("$index,$item")
      }
    3. 遍历map

      1
      2
      3
      4
      5
      6
      7
      val hashMap = HashMap<String, String>()
      hashMap["1"] = "123"
      hashMap["2"] = "234"

      for ((key,value) in hashMap){
      println("$key,$value")
      }
  16. in 跟 ! in

    1. 是否在范围内,范围可以是数字,字符,也可以是实现了Java.lang.comparable接口的类对象实例
    2. 是否在集合内
    1
    2
    3
    4
    5
    6
    7
    8
    9
    fun isNumber(c: Char) = c in '0'..'9'

    fun main(args: Array<String>) {
    println(isNumber('0'))
    //string 实现了Java.lang.comparable
    println("javascript" in "java".."kotlin")

    println("java" !in setOf("java", "kotlin"))
    }
  17. 异常处理

    1. 跟java 一样用try catch finally
    2. 它是表达式
    3. kotlin中函数不需要throws异常
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    fun readNumber(read: BufferedReader): Int? {
    val line = read.readLine()
    return try {
    Integer.parseInt(line)
    } catch (e: Exception) {
    null
    } finally {
    read.close()
    }
    }

    fun main(args: Array<String>) {
    print(readNumber(BufferedReader(StringReader("123q"))))
    }

    以上例子中,如果是java,那么需要throws IOException( 因为read.close()方法 ),但是在kotlin中不需要

  18. 创建集合

    1. kotlin没有自己的集合类,跟java公用
    2. kotlin在java的基础上增加了一些语法糖
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    fun main(args: Array<String>) {
    val hashSet = hashSetOf(1, 2, 3)
    val hashMap = hashMapOf(1 to '1', 2 to '2')
    val arrayList = arrayListOf(1, 2, 3)

    println(hashSet.javaClass)
    println(hashMap.javaClass)
    println(arrayList.javaClass)

    println(arrayList.last())
    println(hashSet.max())
    println(hashMap[1])
    }

    //输出
    class java.util.HashSet
    class java.util.HashMap
    class java.util.ArrayList
    3
    3
    1
  19. 函数声明时候的默认参数

    1. 在java的类中会出现大量的方法重载,kotlin的函数参数可以有默认值,这个特性可以减少很多模版化的重载
    2. kotlin调用方法的时候可以指定参数名称,而且可以不用按方法声明的参数顺序去写,增加了代码易读性。
    3. 因为java中不具有该特性,java调用该代码的时候必须指定全部参数;@JvmOverloads注解可以让这个方法生成对应的java重载方法,这样就java调用的时候就不用指定全部参数了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @JvmOverloads
    fun doSomething(
    param1: String,
    param2: String = "default"
    ) {
    println(param1)
    println(param2)
    }


    fun main(args: Array<String>) {
    doSomething("1")
    doSomething("1", param2 = "2")
    doSomething(param2 = "1", param1 = "2")
    }
kotlin跟java可以随便调用吗
  1. kotlin可以直接在.kt文件中写变量写方法等。

    Test.kt文件如下

    1
    2
    3
    4
    5
    var v1: Int = 10
    fun printlen(str: String): String {
    println("stringValue: $str")
    return str
    }

    java中调用(文件名+Kt是编译之后的class名,getV1跟setV1是编译过程中自动生成的)

    1
    2
    3
    4
    5
    //调用方法
    TestKt.printlen("111");
    //使用变量
    TestKt.getV1();
    TestKt.setV1(2);
  1. kotlin匿名内部类 ,关键字object+类名{ xxx }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Kt {
    //定义匿名内部类
    object Inner{
    fun sayHello(){
    println("hello")
    }
    }

    fun test(){
    //kotlin 调用
    Inner.sayHello()
    }
    }

    public void test(){
    //java调用
    Kt.Inner.INSTANCE.sayHello();
    }

    从java的调用方式可以看出来匿名内部类是单例的。

  1. kotlin使用java中Class对象,kotlin中Class是KClass

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    //J是一个java类
    fun test(clazz: Class<J>) {
    println(clazz.simpleName)
    }
    //Kt是一个kotlin类
    fun test1(clazz: KClass<Kt>){
    println(clazz.simpleName)
    }
    //调用
    test(J::class.java)
    test1(Kt::class)
  2. in在kotlin中是关键字,如果调用的java常量名字是in需要加

    1
    J.'in'
新手常见问题
  1. kotlin中默认的只有基础类型,没有封装类型
  2. kotlin是空安全的,调用返回值是String的java方法时需要用String?来接受返回值,不能用var。var接受的话会自动推导成String!,如果用var接受,当方法返回值是null的时候,可能会有空安全问题(比如调用.length())。
  3. kotlin中没有静态变量跟静态方法

第二章 函数跟lambda闭包

函数特性
  1. 函数参数可以有默认值

  2. 如果只有一个语句可以如下

    1
    fun test() = print("hello")
嵌套函数

函数中可以声明函数

1
2
3
4
5
6
7
8
9
10
fun test3(){
var count =3
fun say(){
if(count >0){
println("hello")
count--
}
}
say()
}
扩展函数
  1. 语法

    1
    2
    3
    4
    5
    6
    7
    //扩展java中的File,注意this
    fun File.printFileName() = print(this.name)

    fun main() {
    val file = File("./kotlin_study.iml")
    file.printFileName()
    }
  2. 使用场景

    • 用于扩展第三方的类
    • 用于扩展java的类
    • 。。。感觉就是很强大
  3. 注意点

    • 扩展函数都是静态的(public static final)
    • 不具有重载的特性(看上去是对象在调用,实际是类在调用)