都2023年了,新建的项目仍是Java
项目,或者你还在写Java
样式的Kotlin
项目,细心看完这篇文章,带你从Java
转到Kotlin
,带你学会Koltin
,从入坑到脱坑
为什么要学习Kotlin
-
Kotlin
是Andorid
官方推荐言语 - 最年来
Google
发布许多新玩意,都是Kotlin
写的,对Kotlin
支持比较友好 -
Compose
你不会Kotlin
怎样学习 - 一些大型开源项目,比方
Okhttp
,Retrofit
,Glide
都改成了Kotlin版本 - 运用协程,让你切换线程更加方便,脱节回调阴间
- 让你的代码更简练
综上所示,笔者认为,Kotlin
如今是一名Android开发工程师所必须要掌握的技术,可是偏偏仍是有许多人不必,不学,所以就写下来这篇文章,带你快速入门Kotlin
,也算是对自己常识的一遍稳固
根底
何为Kotlin
,笔者认为是怎样快速界说变量,常量,new
一个对象,调用一个办法,来看一下Java
是怎样做的
int a = 10;
a = 11;
TextView textView = new TextView(context);
textView.setText(a);
嗯,仍是比较简练的,可是还能够更简练,看一下相同的代码运用Kotlin
怎样完结
fun Test(context: Context?) {
var a = 10
a = 11
val textView = TextView(context)
textView.text = a.toString()
}
解释一下,Kotlin
界说常量是val
,变量为,var
,什么类型,根本不需要,它会经过后边得内容主动推导出来是什么类型的,可是从实质来说,Kotlin
是仍是强类型言语,只不过编译器会主动推导出来他真的类型罢了,然后是不必写new
关键字了,不必写;结束了,get
、set
办法也不必写,直接等,实际上仍是调用了真的get
和set
,原因是经过了属性访问器(accessor)的语法糖方式直接运用等号进行赋值和获取
类
接下来看一下类,点即创立一个Kotlin类型得File,会出来如下弹框
-
Class
和Java
的Class
没什么两样,一般便是一个类 -
File
假如当一个Class
中有两个同级其他类,这个时分就会变为File
,这个一般在写扩展函数的时分运用,扩展函数后边会讲到 -
Interface
和Java
的Interface
相同,一个接口 -
Sealed interface
封闭接口,避免不同model之间的相互调用,比方你再B Model
中界说B Sealed interface
,那么你只能在B Model
中运用这个接口,除此之外,仍是运用此接口完结多承继的操作 -
Data class
实体类,和Java
实体类有什么不同呢,不必写get
,set
办法和一般Kotlin Class
有什么不同呢,首要是必须要有有参结构办法,然后重写了hashCode
和equals
办法 -
Enum class
枚举类,和Java
相同 -
Sealed class
和Sealed interface
差不多,都是限制只能在一个Model
中运用 -
Annotation
界说一个注解 -
Object
这个笔者最喜欢,常用来界说一个单例类,相当于Java的饿汉式 其中比较常用的有Class
,Data class
,Object
总的来说仍是比Java的类型多一点
回来值
为什么要单写一个回来值,由于Kotlin
的所有办法都有回来值,常规的就不说,看下面代码
val a: Unit = printA()
private fun printA() {
print("A")
}
这儿面界说了函数,没有界说任何回来值,可是其实的类型是Unit
,我的了解是Unit
就代表它是一个函数类型和String
相同都是Koltin
类型中的一种,明白了这点就能够了解接下来的操作
val a = if ( x > y) x else y
相当于Java
的三元换算符,假如x
大于y
就等于x
,不然就等于y
,对了Kotlin
是没有三元换算符这个概念的,假如要达到相同作用只要运用if...else...
,同理when
也同样适用于这种操作
仍是一种建立在编译器类型推导的根底上一种写法
private fun getA() = {
val a = 0
a
}
这个函数的意义便是回来了一个数字a
,为什么没有return
它却具有回来值回来值,请注意看这个=
号,编译器给他推导出来了,并且经过lamaba
回来值
还有一个十分特别的回来值 Nothing 什么意思呢 不是null 便是什么也没有 详细能够看一下这篇文章
NULL安全处理
Kotlin是一个null安全的言语下面详细看一下
//界说一个变量
private var a: String? = null
String后边有个?代表,这个变量是可能为null的那么就需要在运用的时分处理它,不然会报错
if (a != null){
//不为null
}else{
//为null
}
//或者加上!!,代表这个时分必定不为null,可是一般不主张这样写,玩呈现null,就会空指针反常
a!!
当然假如确定运用的时分必定部位null也能够这样写
private lateinit var a: String
代表界说了一个变量,我不论之前对它做了什么操作,横竖我运用的时分,它一定是不为null的,当然与之的对应的还有by lazy
延迟初始化,当第一次运用的时分才会初始化,比方这样,当我第一次调用a
的时分,by lazy
的括号内容即托付就会执行给a
赋值,值得注意的是by lazy
不是绑定在一起的 也能够只运用by
意思也是托付,不过要单独写一个托付的实现
private val a: String by lazy { "123" }
扩展函数
扩展函数能够说是Kotlin比较爽的部分,他的实质其实是一个Kotlin的静态办法然后回来了它原本得了类型,比方这段代码
fun String?.addPlus(number: Int): String? {
if (this == null){
return null
}
return this.toInt().plus(number).toString()
}
扩展了String的办法,在String的根底上添加了一个addPlus
办法,然后接受一个number
参数,然后强转为int
类型之后加上number
并回来,这样扩展不必承继也能够在一些类中添加办法,减少了出BUG
的可能性
val str = "1"
val str2 = str.addPlus(2)
看一这段代码的实质,能够知道Koltin和Java是能够相互转化的
public static final String addPlus(@Nullable String $this$addPlus, int number) {
return $this$addPlus == null ? null : String.valueOf(Integer.parseInt($this$addPlus) + number);
}
能够看到,扩展函数的实质是一个静态办法,并且多了一个String类型的参数,这个参数其实便是扩展函数类的实体,运用扩展函数能够实现简化许多操作,比方金额核算就能够扩展String,然后接收一个String,又或者是给textView添加一个功用,同样能够运用,我认为它差不多便是简化了静态工具类的运用,让其更方便,更方便
扩展函数二 let also run apply
还记得上面说到的Kotlin对于null的判别吗,其实具有更快方便的办法便是运用扩展函数看这一段代码
fun stringToInt(str: String?): Int {
return str?.let {
it.toIntOrNull() ?: -1
} ?: run {
-1
}
}
一段链式调用,这也是Kotlin的特性之一,后续有时间会讲,链式调用有好处也有害处,好处是能够更好的代码,害处是一旦运用了过长的链式调用,后期代码保护就会很费事,为什么我会知道,由于我就写过,后期保护的时分痛不欲生,开发一时爽保护两行泪,可是适量运用这种,会让你的代码变得更简练,保护更方便,主要仍是看工程师的把握度。
好了详细看一下代码做了什么工作,首要界说了一个stringToInt
的函数,然后接受了一个String
参数,这个参数能够为null
,然后判别是否等于null
,等于null
回来-1,不能转化为int
回来-1,能够正常转化回来int
值
Ok 先解释一下怎样运用扩展函数做null
判别 ?.let
代表假如str
这个值不为null
,那么就执行it.toIntOrNull() ?: -1
,不然这儿用 ?:
来处理即为null 就走run 然后回来-1
- let 供给了一个以默认值it的空间,然后回来值的是当前执行控件的最后一行代码
- also 供给了一个以默认值it的空间,然后回来值是它自身
- run 供给了一个this的命名空间,然后回来最后一行代码
- apply 供给了一个this的命名空间,然后回来它自身 这儿贴出Kotlin的实现,源码其实很简单
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
代码其实很简单,有爱好能够自己随意玩玩,这儿就以apply
为例剖析一下,首要回来一个泛型T
,这个T
便是调用者自身,然后接口了一个black
的函数,这个函数便是实际在代码中apply
供给的空间,然后执行完结后,然后调用者自身,这样就和上文对应上了,apply 供给了一个this的命名空间,然后回来它自身,也能够仿照实现一个自己myApply
哈哈哈,
结语
这篇文章其实原本想写的十分多,还有许多关键字没有介绍,比方by,inline
,受限于篇幅问题,暂时把最根底的写了一写,以后会逐步完善这个系列,在写的过程,也有一些是笔者运用起来相对来说比较少的,就比方Sealed interface
这个接口,之前就彻底不了解,在写的时分特意去查询了一下材料,然后自己测试了一番,才了解,也算是促进了自己学习,希望能够共同进步