最强总结 | 带你快速搞定kotlin开发(上篇)

2020-11-25 11:27:06 浏览数 (1)

1.1 函数:

代码语言:javascript复制
fun sum(a: Int, b: Int): Int { 
    return a   b
}  
// 对于只有一行的函数,kotlin可以这么简写,爽不?
fun sum(a:Int, b:Int): Int = a   b

可以看到函数的声明是通过fun关键字的,函数的参数类型和参数名的位置跟Java是相反的,中间使用 : 分隔,函数的返回类型是放在最后的,当然也是使用 : 进行分割的,如果没有返回值的时候可以省略或者使用Unit,相当于Java的void

1.2 变量:

代码语言:javascript复制
var age:Int = 18
val name:String = "Kotlin"
val person = Person()

使用var来声明可读可写变量,使用val来声明只读变量(引用不可变)。 val可以理解为Java中的属性声明加上了final关键字(将kotlin的字节码反编译成Java一看就知道了),其实kotlin是更倾向于推荐使用val来声明变量,这是一种防御性的编码思维模式,目的是减少程序出错或者变的更加安全。 可以看到实例化Person对象时,并没有声明变量类型,这就是Kotlin的“类型推断”,会自动推断出是Person类型的变量,而且是不需要Java中的new关键字的。

1.3 继承和实现接口

代码语言:javascript复制
class MyActivity: Activity(), View.OnClickListener {
// 省略
}

一看就懂,不用多说吧。注意加上(),如果你的kotlin类能够被继承,需要使用open关键字,因为默认是final的:

代码语言:javascript复制
open class Person {
    constructor(age: Int)
    var age: Int = 0
}
// 当你的构造函数调用父类的构造函数时,要去掉Person后面的()
class Man: Person {
    // 使用super调用父类的构造器
    constructor(age: Int): super(age)
}

1.4 空安全设计

代码语言:javascript复制
// 不可空类型
val person: Person

// 可空类型
val person2: Person?

那么对于可空类型的变量在调用时可以选择使用:

代码语言:javascript复制
val person: Person? = null
// 安全调用
person?.age = 18
// 强行调用
person!!.name = "kotlin"

使用调用符,就算person是null的也不会出现空指针了,相当于Java中的判空了。当然如果你能确认person不会为空,可以使用!!强行调用符

1.5 lateinit关键字

代码语言:javascript复制
lateinit var person: Person
person = Person()

我们总有场景在声明的时候不知道赋什么值,在后面才去赋值的场景,那么就可以使用lateinit关键字。但是只能在以下场景下使用:

  • var声明的变量
  • lateinit修饰的变量不可空、不能是基本数据类型、不能有初始值
  • 构造器中初始化的变量不需要使用lateinit关键字

1.6 类型判断

代码语言:javascript复制
if(p is Person) {
    p.age = 20
}
val man: Man = Person()
val per: Person = man as Person

is关键字类似于Java中的instanceof,判断是否是什么类型,判断不是什么类型可用!is,可以看到kotlin有个小优化,就是p在条件成立时,不需要再强转了,直接被认为是Person的类型,进而可以使用Person的API。当你真的需要强转时可以使用asas?关键字,带?的在强转失败时并不会抛异常,而是返回一个null值

1.7 获取class对象

代码语言:javascript复制
// Person.kt
Person::class
// Man.java
Man::class.java

区别于Java,kotlin要兼容Java,所以获取Java的class和kotlin的class略有不同,kotlin的class使用::class,而在kotlin中获取Java的class可以使用::class.java

1.8 setter和getter

代码语言:javascript复制
class Person {
    var age: Int? = null
}
// 等价于
class Person {
    var age: Int? = null
        get() {
            return field
        }
        set(value) {
            field = value
        }
}

kotlin在声明非private的属性时,会默认生成对应的公开的set和get方法,当你在Java中访问时必须:

代码语言:javascript复制
Person p = new Person();
p.setAge(20);

不过如果你就要直接访问age属性也是可以的,使用@JvmField注解:

代码语言:javascript复制
// kotlin
class Person: Any {
    // kotlin构造函数使用constructor关键字
    constructor()
    // 加上这个注解,编译器只会生成一个public的属性,而不生成set和get方法
    @JvmField var age: Int = 19
}
// java
public class Test {
    private void some() {
        Person p = new Person();
        p.age = 20;
    }
}

1.9 数组

代码语言:javascript复制
open class Person {
    constructor(age: Int)
    var age: Int = 0

    fun test() {
         // 会有装箱拆箱的操作,会影响性能
        val ages = arrayOf(14, 15, 16)
        // 基本数据类型使用对应的函数,比如intArrayOf()函数避免拆装箱的过程
        val ages2 = intArrayOf(14, 15, 16)
    }
}

可以使用arrayOf()来创建数组。对于基本数据类型优先使用对应的函数进行创建。

1.10 静态函数和属性

代码语言:javascript复制
// 方法在类的外面【包级函数】或者叫【顶层函数】
fun getSomething(): Int {
    return 0
}

class Person {}

// 在Java中使用类名 Kt后缀直接访问
PersonKt.getSomething();

// 在kotlin文件中调用更加方便,只需要导包,不需要加类名
// 但是这种方式并不有利于阅读,会和类中的函数搞混淆
getSomething()

可以看到我们可以直接在文件里面声明函数,然后通过类名 Kt的方式直接调用。这种叫包级函数

代码语言:javascript复制
object Person {
    fun getSomething(): Int {
           return 0
    }
}

// kotlin中调用
Person.getSomething()
// java中调用
Person.INSTANCE.getSomething();

其实使用object创建类的时候,默认会生成一个单例对象,当我们使用类名来直接调用的时候,其实是通过默认的单例对象进行调用的。本质上和我们java中的静态方法还是不同的。

代码语言:javascript复制
class Person {
    companion object {
        fun getSomething(): Int {
            return 0
        }
    }
}

// kotlin
Person.getSomething()
// java,好麻烦,但是可以使用注解@JvmStatic来让编译器编译成静态的
Person.Companion.getSomething();
// java 使用注解后就可以在Java中直接调用了
Person.getSomething();

使用companion object(伴生对象)的方式相当于有一个内部类的单例对象,这些通过kotlin的字节码反编译成Java文件就可以看出来。看起来比直接使用static关键字麻烦多了,那kotlin为啥要去掉static这个关键字呢?那得问当初设计kotlin语言的人了,从面向对象的角度来说,这么设计的确更符合万物皆对象的理念,因为static只跟类有关,而不是和对象有关。

所以,我们可以看出来使用object貌似和创建默认对象有关系,不错,比如匿名内部类(本质上就是创建一个对象)

代码语言:javascript复制
    var view = window.decorView
    fun test() {
        view.setOnClickListener (object : View.OnClickListener{
            override fun onClick(v: View?) {

            }
        })
    }
    // 当然可以简写成下面这样
    fun test() {
        view.setOnClickListener {

        }
    }    

1.11 小技巧

可以使用 ${} 来做字符串模板:

代码语言:javascript复制
val age = 18
val info = "我是一个${age}岁的帅哥"

支持多行字符串,使用三个引号"""

代码语言:javascript复制
    val info = """
        hhahha
        jaa
        sdfjdkjs
        jsafjs
    """.trimIndent()

判断数据范围和switch的使用:

代码语言:javascript复制
// 如果年龄在10到30(包括30)
if(age in 10..30)
// 使用when取代Java中的switch,并且是支持表达式的
    when(age) {
        18->{

        }
        19->{

        }
        in 20..30-> {
        }
    }

在 Java 中通过 「 类名.this 例如 Outer.this 」 获取目标类引用 在 Kotlin中通过「this@类名 例如this@Outer」获取目标类引用

0 人点赞