Kotlin的关键知识点

变量

kotlin的变量分为可空类型和不可空类型。在变量定义时,如果加上问号,表示改变量是一个可空类型,如果变量没有使用问号修饰,则变量是不一个不可控类型。

变量调用

调用符

对于可空类型的调用,可以使用两种调用符号:

  • ?. :使用该符号对变量进行调用时,如果变量为空,调用逻辑不会执行。
  • !!. :对变量进行强行调用,如果变量为空,则会抛出异常。

类型判断与转化

kotlin中使用is 进行类型的判断。使用as进行类型的强转。如果类型转化的逻辑基于类型判断的逻辑,则不需要进行类型强转,这是kotlin的只能转换。如下:

if(a is A) {
	//val newA: A = a as A  在kotlin中这一行可以去掉,原因是智能转换
}

定义一个类

public class Student{
	//@JvmField该注释的作用是能够让java直接访问这个变量
	var username: String? = null
	var password:String? = null
	//提供get和set方法的属性需要按照如下实现
	var code:String? = null
		set(value) {
			fileld =  value
		}
		get(){
			return field
		}
}

constructor(){
}

constructor(username:String?, password:String?, code:String?){
		this.username = username
		this.password = password
		this.code = code
}

类系统

在kotlin中所有的类都继承自Any
Unit类型对应java中的void

方法的写法

可见性关键字+fun+方法名+参数+返回类型

private fun test(param: Param):Bool{
}

Kotlin自定义view

例子如下:

class CustomView : AppCpmpatTextView{
	constructor(context: Contenxt) : this(context, null){
	}

	constructor(context: Context, attr: AttributeSet ?) : super(context, arrt){
		...代码略
	}
}

Kotlin数组

使用ArrayOf尽心数组的创建
在Kotlin中数组的长度使用size类进行获取

int转float

Kotlin从int转化为float直接使用toFloat

Kotlin静态函数

kotlin中没有static关键字,实现静态方法有三个方案

  • 最方便的方法是定义在文件中。直接在文件中实现方法。这种函数叫做顶级函数。这样生成的方法在java中调用使用文件名.function()进行调用。对于这种情况,也可以对类名进行修改,只需要通过注解就可以做到。
    对于在文件中声明的方法,在文件的第一行加上注解,声明一个类名,即可指定java调用kotlin包函数时使用的类。如下:
@file:JvmName("TestUtils")

其中@file表示是对文件进行注解;

  • 使用Object声明类,Object类内部所有的方法都会变成静态方法。如下
object TestUtils {
	fun test(){}
}

对于这种方法,使用类名TestUtils.test()进行调用,如果在java中进行调用,使用Java.INSTANCE.test()进行调用。这种在本质上并不是静态方法,而是创建了一个object单例对象。

  • 对于一个普通的类,如果需要创建一个静态方法,使用伴生对象来进行创建。如下:
class BaseApplication :  Application() {
	companion object {
		fun currentApplication(): Context{
			....
		}
	}
}

在Java中进行调用时,使用BaseApplication.companion.currentApplication来进行调用。这种实现在本质上来说,也是一个单例函数。

  • 在kotlin中想要实现一个真正的java中的静态方法,需要加上一个注解:@Jvmstatic,这样在java中调用的时候可以直接使用类名.方法名进行静态函数的调用。

单例实现

在使用java的时候,我们经常会用到单例:

public class Test {
	private Test(){
	}

	public static final Test INSTANCE = new Gson(); 
}

在Kotlin中只需要使用object声明类可以做到。

匿名内部类

在kotlin中匿名内部类使用object进行实现。如下:

//其中Callback是一个接口类型
testUtil.test(object: Callback {
	override fun fun1(){
		//方法1实现
	}
	override fun fun2(){
		//方法2实现
	}
})

区间判断

在kotlin中使用…可以进行区间的表示,如下:

//java中
if(size >= 200 && size <300)
//kotlin中
if(size in 200..299)

when关键字

在kotlin中,使用when可以实现类似java中switch的功能,可以替换掉if else结构。但是不同的是,when可以直接跟表达式,而java中的switch只能是byte、short、int 或者 char类型。

枚举

java中使用enum直接声明也给枚举类型,但是在Kotlin中使用num class来声明一个枚举类型。

静态变量

class Test{
	companion object {
		//const充当的是java中final的作用,是常量成为编译期常量
		const val FINAL_VALUE = "final string"
	}
}

列表

Kotlin中可以使用ArrayListOf创建一个列表

静态内部类

在Kotlin中默认的内部类是静态内部类,如果创建非静态内部类,需要用inner修饰class。

初始化

如果Kotlin中构造器使用的是著构造器,初始化的代码直接使用init来进行包裹即可进行初始化:

internal class Test(data:String) : FatherTest(data) {
	init{
		//这里放置初始化代码
	}
}

构造属性

在Java中经常使用到的一种初始化的方式是

public calss Test{
	private String name;
	private int age;
	Test(String name, ing age) {
		this.name = name;
		this.age = age;
	}
}

在Kotlin中可以使用以下方案替换

class Test(var name:String, var age:Int){}

即在参数中使用var关键字对变量进行修饰。

data class

在开发中常用到一种数据,直接进行string序列化打印。

  • 在Kotlin的data class中,equals方法的对比是基于构造方法中的参数来进行实现的。
  • 在Kotlin中符号’== ‘对比是通过equals进行对比,只有’=== '才是通过地址来进行对比,目的是对比两者是不是同一个对象。
  • Kotlin中的data calss会自动生成toString、hashCode、equals方法,此外,还会生成copy函数,作用是进行数据拷贝。

data class解构

在Kotlin中,可以通过解构来实现多返回值的作用。如

data class Response(var name: String, var age: Int, var code: String){
}
fun getResult(): Response(){
}

//通过解构获取多个返回值,结果要和构造方法中的参数保持一致
val(name: String, age: Int, code: String) = getResult()

ps:只有data class才有解构的功能,如果是一个普通的class,想要使用解构的话,需要手动实现component方法。

Kotlin中?:符号的使用

在java的编写中经常使用如下场景

TestClass condition = ...
if(condition != null) {
	String data = condition.getName()
}

在kotlin中,可以使用符号?:进行相同作用的实现,如下

val data = condition.getName()?:"一个默认值"

Kotlin高级函数举例

在Kotlin中,对于集合,如ArrayList,可以直接调用forEach方法进行遍历,例如,在如下场景中:

val destList = ArrayList<Data>()
for(data: Data in srcList) {
	if(data.type == Type.Type1) {
		destList.add(data)
	}
}

可以直接通过Kotlin的高级方法进行优化。

  • 使用forEach优化如下:
srcList.forEach({data:Data->
	if(data.type == Type.Type1) {
		destList.add(data)
	}
})
  • 对于Kotlin,如果方法的最后一个参数是一个lambda表达式,可以将表达式提取到方法外边,如下
srcList.forEach() {data:Data->
	if(data.type == Type.Type1) {
		destList.add(data)
	}
}
  • 如果函数参数只有一个lambda,那么当前方法的空的小括号也可以省略,进一步简化如下:
srcList.forEach{data:Data->
   if(data.type == Type.Type1) {
   	destList.add(data)
   }
}
  • 基于Kotlin的类型推断,还可以进一步简化如下,把类型省略:
srcList.forEach { data->
	if(data.type == Type.Type1) {
		destList.add(data)
	}
}
  • 在Kotlin中如果lambda只有一个参数,那么参数也可以省略,使用it代替,因此,上述写法还可以简化为如下样式:
srcList.forEach {
	if(it.type == Type.Type1) {
		destList.add(it)
	}
}
  • 在Kotlin中数组和列表带了filter操作复,因此对于上述结果使用filter进一步简化如下:
val destList: List<Data> = srcList.filter { it.type == Type.type1 }

到这里,Kotlin中经常用到的一个例子就简化完成了。

Kotlin中函数可以嵌套

在Kotlin中,函数可以嵌套,被嵌套的函数只能被外部函数使用且被嵌套的函数可以访问外部函数中的成员。

fun test(){
	fun innerTest(){}

	innerTest()
}

但是需要注意的是,嵌套函数被调用的时候会生成一个对象,例如上面的test函数每次点用innerTest函数的时候,会生成一个innTest函数对象。因此如果外部函数被频繁调用,则注意注意内部函数的使用,防止创建过多的对象出来,影响性能。

Kotlin中扩展方法或者扩展属性

在kotlin中,可以对已有类进行方法或者属性的扩展,如下图,两个方法的作用是扩展一个可以获取到第一个子view的属性,和获取指定index对应的子view

val ViewGroup.firstChilc: View
    get() = getChildAt(0)

fun ViewGroup.getSpecialView(index: Int): View{
    return getChildAt(index)
}

Kotlin的inline关键字

Kotlin支持内联函数,在Kotlin中,如果使用inline关键字修饰一个方法,那么该方法为内联方法,在编译的时候会把方法实现直接编译到调用的地方,使用如下:

fun main(args: Array<String>) {
    test()
}

inline fun test(){
    Log.i("tag", "test")
}

通过对Kotlin进行反编译程java, 可以看到直接把源码编译到了main方法中,如下:

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkNotNullParameter(args, "args");
      int $i$f$test = false;
      Log.i("tag", "test");
   }

内联函数的作用是可以减少调用栈。
但是内联函数会增加编译时间。如果方法被频繁调用,则会使代码膨胀。因此对于普通函数,使用inline关键字的意义不大。inline 方法的一个比较常见的应用场景是,函数作为参数传递的时候。例如,在Kotlin中,支持函数作为参数传递,如下:

fun main(args: Array<String>) {
    val testObj = TestClass()
    testObj.setOpListener(::opTest)
}

class TestClass{
    fun setOpListener(listener: (Int) -> Unit){
        //逻辑代码
        listener(3)
    }
}

fun opTest(testInt: Int) {}

对于这种情况,反编译以后我们可以看到再调用setOpListener的时候会传一个对象进去,如下:

   public static final void main(@NotNull String[] args) {
      Intrinsics.checkNotNullParameter(args, "args");
      TestClass testObj = new TestClass();
      testObj.setOpListener((Function1)null.INSTANCE);
   }

在这种场景下,就比较适合使用inline关键字,可以减少对象的创建,把源代码改成如下格式

fun main(args: Array<String>) {
    val testObj = TestClass()
    testObj.setOpListener(::opTest)
}

class TestClass{
    inline fun setOpListener(listener: (Int) -> Unit){
        //逻辑代码
        listener(3)
    }
}

fun opTest(testInt: Int) {}

所以,对于inline关键字,减少调用栈只是其中的一方面,对于函数参数类型的调用来说,更重要的作用是减少对象的创建。

Kotlin委托

Kotlin中委托有点java总代理的味道。具体的使用方法可以直接看kotlin官方文档,见https://www.kotlincn.net/docs/reference/delegated-properties.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值