为项目添加 Kotlin 言语的支撑

假如是现有的项目要支撑 Kotlin,只需求像下面这样操作,把两个build.gradle中标注的代码对应贴到项目里就能够了。

  • 项目根目录下的build.gradle

    01 Kotlin 的变量、函数和类型

  • app 目录下的build.gradle

01 Kotlin 的变量、函数和类型

Kotlin界说变量

  • var: variable的缩写,声明变量的润饰符

var view: View

  • val: value的缩写,声明只读变量的润饰符,只能复制一次,不能修正

val a: Int=10

Kotlin类型揣度

假如声明时直接赋值,则能够不写变量类型。例如:val a=10

留意:类型揣度与动态类型不同,如下所示。

  1. 动态类型:变量类型在运转时可改动。
  2. 类型揣度:代码中不用写变量类型,编译器会帮忙补上。

因此,Kotlin 是一门静态言语。

01 Kotlin 的变量、函数和类型

Kotlin 空安全规划

空安全规划的意图:为了避免调用空目标,呈现NullPointerException错误 Kotlin中一切变量不允许为空

lateinit

作用:让IDE不要对这个变量进行查看和报错 适用场景:我很确定这个变量到运用的时分不为空,可是在声明的时分暂时还不能给它赋值

lateinit var view: View

可空类型:类型后加? 作用:免除变量的非空约束

var name:String? = null

留意:”?”包含了非空查看.

Java中运用或许为空的变量时,我们一般会经过写if(name==null)来查看变量是否为空。可是if(name==null)查看不一定能保证name不为空,由于在多线程的状况下,别的线程或许会在查看非空后,将name的值变为null。

Kotlin中运用或许为空的变量的做法:(线程安全)

class User{
    var name:String? = null
}
...
 println(name?.length) //会对变量做一次非空承认后再调用办法
 println(name!!.length) //也能够用双感叹号,写法不同而已

总结:报错状况

  • 变量需求手动初始化,所以不初始化会报错
  • 变量默许非空,所以初始化时赋值为null也报错
  • 用?设置的可空变量运用时报错

留意:讨论可空/不行空,都是针对变量在运用时的状况

Kotlin的函数声明

  • 以 fun 关键字最初
  • 返回值写在了函数和参数后面
fun cook(name: String): Food {
    ...
}

假如没有返回值:

fun main(): Unit {}
// Unit 返回类型能够省掉
fun main() {}

留意:函数参数有可空控制,传参时留意可空/不行空的匹配

// 可空变量传给不行空参数,报错
var myName : String? = "rengwuxian"
fun cook(name: String) : Food {}
cook(myName)
// 可空变量传给可空参数,正常运转
var myName : String? = "rengwuxian"
fun cook(name: String?) : Food {}
cook(myName)
// 不行空变量传给不行空参数,正常运转
var myName : String = "rengwuxian"
fun cook(name: String) : Food {}
cook(myName)

Kotlin中的特点的 getter/setter 函数

实例:在如下比如中,调用 hello.name 办法 , 实际上调用的是 hello.setName 办法

class Hello {
    var name = "Tom"
    var age = 18
}
fun main() {
    var hello = Hello()
    hello.name = "Jack"
}

暗地字段

在Kotlin中特点作为一级言语特性,通常状况下集暗地字段(field储值变量)+ 拜访器(getter读拜访器、setter写拜访器)于一身,无论是声明【var age: Int】、赋值【user.age = 18】、取值【println(user.age)】,从字面上看都是 age 这个特点自身,是一个全体。而只要在我们需求自界说拜访器的时分才会区别这三者。

例如自界说 setter 的时分,假如不写成暗地字段field = value,不管是 age = value 还是 this.age = value 都会报错,由于特点 age 的赋值就是setter,明显不能递归调用。

假如特点的拜访器至少有一个运用默许完成,或许自界说的拜访器中运用了 field ,那么就会提供暗地字段,用 field 关键字表示,首要用于自界说 getter/setter 时运用,也只能在 getter/setter 中拜访。

实例:

class Demo{
    var id: Long = 0
        get() = field
        set(value) { field = value }
}

个人理解:field是一个中转变量

Kotlin中的基本类型

在 Kotlin 中,一切东西都是目标,Kotlin 中运用的基本类型有:数字、字符、布尔值、数组与字符串。

var number: Int = 1 // 还有 Double Float Long Short Byte 都相似
var c: Char = 'c'
var b: Boolean = true
var array: IntArray = intArrayOf(1, 2) // 相似的还有 FloatArray DoubleArray CharArray 等,intArrayOf 是 Kotlin 的 built-in 函数
var str: String = "string"

什么是装箱?

简略来说,原先在 Java 里的基本类型,类比到 Kotlin 里面,条件满意如下之一就不装箱:

  • 不行空类型。
  • 运用 IntArray、FloatArray 等。

Kotlin中的类与目标

Kotlin写法和Java写法的不同

//Kotlin
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        ...
    }
}
//Java
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        ...
    }
}

写法比照

比照点 Java Kotlin
可见性 需求写明 默许为public,能够省掉
类的承继的写法 用extends :
结构办法的写法 public MainActivity() { }(可省掉) 单独用了一个constructor关键字来和其他的fun做区别:class MainActivity constructor() : AppCompatActivity() { }
override @Override是注解的方式 override变成了关键字,省掉了protected关键字,也就是说,Kotlin 里的override函数的可见性是承继自父类的
类的承继的写法 MainActivity 可承继,由于Java 里只要加了final关键字的类才是 final 的。 MainActivity 无法承继(无法作为父类),由于Kotlin 里的类默许是 final 的
实例化一个类 Activity activity = new NewActivity(); var activity: Activity = NewActivity()

Kotlin的open关键字

Kotlin的类默许不行承继,所以要想让Kotlin里的MainActivity能够承继:运用open关键字

open class MainActivity : AppCompatActivity() {}

可是要留意,此时 NewActivity 仍然是 final 的,也就是说,open没有父类到子类的遗传性。 override是有遗传性的,假如要封闭override的遗传性,只需求这样即可:

open class MainActivity : AppCompatActivity() {
    // 加了 final 关键字,作用和 Java 里面相同,封闭了 override 的遗传性
    final override fun onCreate(savedInstanceState: Bundle?) {
        ...
    }
}

Kotlin的abstract关键字

Kotlin中abstract关键字润饰的类无法直接实例化,而且通常来说会和abstract润饰的函数一起呈现:

abstract class MainActivity : AppCompatActivity() {
    abstract fun test()
}

可是子类假如要实例化,还是需求完成这个 abstract 函数的:

class NewActivity : MainActivity() {
    override fun test() {}
}

Kotlin中的类型的判断和强转

Kotlin中运用is关键字进行「类型判断」,而且由于编译器能够进行类型揣度,能够协助我们省掉强转的写法:

//Kotlin中的写法
fun main() {
    var activity: Activity = NewActivity()
    if (activity is NewActivity) {
        // 的强转由于类型揣度被省掉了
        activity.action()
    }
}
//相当于Java中这么写
void main() {
    Activity activity = new NewActivity();
    if (activity instanceof NewActivity) {
        ((NewActivity) activity).action();
    }
}

Kotlin中类的强转调用:运用as关键字

fun main() {
    var activity: Activity = NewActivity()
    (activity as NewActivity).action()
}

更安全的强转写法:运用as?,能够更高雅地处理强转犯错的状况。

fun main() {
    var activity: Activity = NewActivity()
    // '(activity as? NewActivity)' 之后是一个可空类型的目标,所以,需求运用 '?.' 来调用
    (activity as? NewActivity)?.action()
}