【Kotlin】学习小记-基础篇

it2026-06-09  1

Kotlin学习小记-基础篇

Kotlin的介绍入门基础篇属性声明关于val和final的小Tips 参数1.可变参数2.命名参数 函数返回值1.默认返回Unit值2.返回Nothing值情况 函数表达式1.单表达式函数2.成员函数3.局部函数4.尾递归函数 类1.抽象类2.嵌套类和内部类3.枚举类 构造函数和初始化块初始化块主构造函数次构造函数 对象声明对象表达式伴生对象(Companion Object)Kotlin里特别的类数据类(Data class)密封类(Sealed class)

这是一份大概的kotlin学习目录纪要,大部分内容摘自自学时的笔记。内容不够完全,有需要详细了解的地方,还需要自己单独去查阅。主要是供给android开发人员由Java转kotlin的码畜们。

附上一份android进阶的思维导图,无论是学习还是巩固,供参考。

Kotlin的介绍

注:本文为自学笔记,仅供参考,内容是自己根据自己的情况来进行标注着重点的。欢迎各位多多指教~

kotlin它是基于JVM的编程语言,它可以编译成java字节码,也可以编译成javaScript,方便在没有JVM的设备上运行。

关于kotlin的特点介绍如下两点:

kotlin和Java可以互调使用 让你的项目可以根据需要,自由切换两种语言的使用;kotlin是一门函数式编程语言减少崩溃,提升体验:

可以通过在 Java 代码中使用 @Nullable 和 @NonNull 等注解来确保 Kotlin 代码获得正确的可空性推断。 整体上看,Kotlin 的空安全特性帮助点评 Android 应用将空指针导致的崩溃从日均 3 个降低至 0。 Google Play 排名前 1,000 的应用,发现使用 Kotlin 的应用与不使用 Kotlin 的应用相比,其用户崩溃率低20%。

入门基础篇

属性声明

声明属性:var和val var:可变变量;声明的属性可以有getter,setter方法。

var nickName:String="Max" fun changeValue2(){ nickName="Sherry" } 操作:将nickeName变量从值Max修改为Sherry 结果:执行成功。

val:只读变量;声明的属性只有gette方法;类似于java中的final变量;它在创建时必须初始化,以后不可修改。

val sex:String="Female" fun changeValue(){ sex="Male" } 操作:将sex只读变量从Female变为Male 结果:报错Val cannot be reassigned 结论:val是只读变量,赋值后不可修改

在实际开发中,定义变量的时候,你会发现,kotlin不允许未初始化的变量。如何解决? lateinit 延迟初始化变量。值得注意的是,使用该变量的时候,要确保其不为null。

lateinit var name:String fun way(){ print(name) }

关于val和final的小Tips

在java中使用final修饰的参数,在kotlin中函数参数可以不用写val关键字,因为它默认就是final修饰符。

参数

1.可变参数

用vararg修饰参数,kotlin的可变参数一般是函数的最后一个参数

fun <T> toList(vararg items:T):List<T>{ val result=ArrayList<T>() for (item in items){ result.add(item) } return result } fun main(arrays:Array<String>){ val list=toList("java","kotlin","python","scala") println(list) }

在toList里面也可以直接放入数组。 step1:建立数组,存入内容 step2:调用toList(*array)。 在stpe2里面,参数名array前面多了一个 * 号。它表示解包数组,能够让每个数组中的每个元素在函数中被作为单独的参数。

fun main2(arrays: Array<String>){ val array= arrayOf("java","kotlin","python","scala") val list=toList(*array) print(list) }

2.命名参数

sum函数内有两个参数,x=0的一个默认参数,参数y。 在调用函数时,命名参数则是y=1,为y指定参数的值。

fun sum(x:Int=0,y:Int):Int{ return x+y } fun test(){ sum(y=1) //相当于 sum(0,1) }

当y值使用默认值时:

fun sum(x:Int=0,y:Int=2,z:Int=1):Int{ return x+y+z } fun test(){ sum(1,z=5) //类似于sum(1,2,5) }

函数返回值

接接接下来,就是我们kotlin很重要的一个part了,什么事孤独终老…呸呸呸!函数的part!

1.默认返回Unit值

关于kotlin内函数的返回,它没有java中的void,但是函数始终默认会返回一个Unit类型。

fun test1():Unit{ println("Hello") }

Unit返回值可以被省略:

fun test1(){ println("Hello") }

2.返回Nothing值情况

fun forNothing():Nothing{ while (true){ println("do nothing") } } fun mainNothing(){ forNothing() println("run here?") }

结果: do nothing 结果里并没有打印 run here? 所以如果返回值为 Nothing ,则Nothing表达式之后的所有代码都不会执行。

函数表达式

1.单表达式函数

fun sum1(x:Int=0,y:Int):Int{ return x+y }

当函数为单个表达式时,可以省略函数体的花括号。 等价于:

fun sum1(x:Int,y:Int):Int=x+y

也等价于:

fun sum1(x:Int,y:Int)=x+y

它根据编译器推断函数的返回类型。

2.成员函数

在类或对象内部定义的函数。这点和java一致。

3.局部函数

指在一个函数中去定义另一个函数,类似于内部类。 局部函数可以访问外部的局部变量,甚至闭包

4.尾递归函数

在kotlin中实现尾递归的条件: 1.使用tailrec关键字。 使用该关键词后,编译器会优化该递归,从而避免堆栈溢出的问题。 2.在函数最后进行递归调用

接下来; kotlin的类和java中的类,这东西就是,横看成岭侧成峰,远近高低各不同,来吧,看看是峰还是林。

1.抽象类

含有抽象方法的类,为抽象类。这一点和java的概念一致。

2.嵌套类和内部类

嵌套类:定义在某一个类内部的类。嵌套类不能访问外部类的成员,除非嵌套类变成内部类。

class OuterClass{ val str:String="this is a outer" class Nested{ fun foo()= println("") } } fun main(args:Array<String>){ OuterClass.Nested().foo() }

内部类:

class Outter2{ val str:String="this is property outter" inner class Inner{ fun foo()= println("$str") } } fun main(args: Array<String>){ Outter2().Inner().foo() }

3.枚举类

kotlin的枚举条件:enum和class关键字

enum class Color constructor(var colorName:String,var value:Int){ RED("红色",1),GREEN("绿色",2),BLUE("蓝色",3) }

枚举类的属性不需要写在枚举类内部,每个枚举都是枚举类的实例。

构造函数和初始化块

kotlin的构造函数可以包括,一个主构造函数+N个次构造函数

初始化块

init块作为初始化块的前缀。

看到这里是不是你有些累了?那…看一篇舔狗日记,来放松一下吧。继续往下走

主构造函数

class Constructor2 constructor(){ init { println("test constructor2") } }

在此代码中,constructor作为构造函数的函数名,此时可省略函数名。

省略后的代码如下:

class Constructor2{ init { print("test constructor2") } }

+ 主构造函数可以省略constructor关键字,无论主构造器是否包含有参数

class Constructor2 constructor(){ init { println("test constructor2") } init { println("test init2") } init { println("test init3") } }

执行结果:

test constructor2 test init2 test init3

+ 初始化块有多个,调用主构造函数时会按照初始化块的顺序执行。

次构造函数

+ 次构造函数,使用constructor作为函数名,但不能省略函数名。 + 次构造函数调用之前必须调用主构造函数,次构造器函数可以包含代码。

/** * 次构造函数 */ class Constructor4(str:String){ init { println("$str") } //this(str1) 调用主构造函数以及它的初始化块 constructor(str1:String,str2:String):this (str1){ println("$str1"+"$str2") } fun foo()= run { println("this is foo function!") } } fun mainConstructor4(args:Array<String>){ val obj=Constructor4("testConstructor4.1","testConstructor4.2") obj.foo() }

执行结果:

testConstructor4.1 testConstructor4.1 testConstructor4.2 this is foo function

次构造函数的特点: + 主构造函数的属性可以使用var,val修饰,次构造函数不能用这些修饰。 + 次构造函数需要依托给主构造函数,调用次构造函数时会先调用主构造函数以及初始化块。

对象声明

Object关键字修饰对象: 通过对象声明可以实现单例模式

object Singleton{ fun printSingleton()= println("just println singleton") } fun main(args: Array<String>){ println(Singleton.printSingleton()) }

将如上代码进行反编译,我们可以看到对象声明类似于 饿汉模式。

它是延迟初始化的,只有当第一次使用printSingleton()方法时,Singleton才会初始化。

对象表达式

它类似于Java中的匿名内部类。

tv_main_click.setOnClickListener(object :View.OnClickListener{ override fun onClick(p0: View?) { println("print max's hello") } })

它相对于java的匿名内部的特点如下: + 支持实现多个接口 + 可访问非final修饰的变量

伴生对象(Companion Object)

kotlin中没有静态属性和静态方法,我们用Companion Object来解决它这一问题。简而言之,它就是代替Java中的static。 伴生对象初始化的时间是:类加载时初始化

class PersonInfo{ companion object{ private var name:String="Max" private var age=20 private var color="blue" fun changeLikeColor(color:String){ this.color=color } fun printColor(){ println("This $this.name is $this.age and she like $this.color") } } } fun main(args: Array<String>){ PersonInfo.changeLikeColor("black") println(PersonInfo.printColor()) PersonInfo.changeLikeColor("orange") println(PersonInfo.printColor()) }

运行结果:

This Max is 20 and she like black This Max is 20 and she like orange

Kotlin里特别的类

数据类(Data class)

Data数据类型,它是由final修饰的类型,不可被继承。

data class TestData(var name:String) data class TestUser(var name:String,var password:String,var testData:TestData) fun main(args: Array<String>){ var user1=TestUser("Max","123456", TestData("TestDataUserInfo1")) var user2=user1.copy() println(user2) //判断data class的copy是否为浅拷贝.若二者的address指向的内存地址相同,说明data的copy为浅拷贝,否则为深拷贝。 println(user2.testData===user1.testData) var user3=user1.copy("Caroline") println(user3) var user4=user1.copy(password = "asdfgh") println(user4) }

执行结果为:

true TestUser(name=Caroline, password=123456, testData=TestData(testData=TestDataUserInfo1)) TestUser(name=Frank, password=asdfgh, testData=TestData(testData=TestDataUserInfo1))

tips:===比较的是内存地址

密封类(Sealed class)

密封类一般和when语句搭配使用,从功能上而言,更类似于枚举。

sealed class Normal(val name:String) class Dog(dogName:String):Normal(dogName) class Cat(catName:String):Normal(catName) class Deer(deerName:String,val color:String):Normal(deerName) fun greetNormal(normal:Normal)= when (normal){ is Dog->"print ${normal.name}" is Cat->"print ${normal.name}" is Deer->"print ${normal.name} the color is ${normal.color}" } fun main(array: Array<String>){ println(greetNormal(Dog("发财"))) println(greetNormal(Cat("恭喜"))) println(greetNormal(Deer("flash","yellow"))) }

执行结果:

print 发财 print 恭喜 print flash the color is yellow

密封类特点: 密封类是一个抽象类 密封类的所有子类要么在密封类中,要么跟密封类在同一文件中,密封类的子类的子类,可在任意位置。 若和when语句联合使用时,is语句可涵盖所有的情况,则无需添加else语句。

以上的内容为kotlin很基础的入门篇,对我来说,很重要的就是对于函数的使用部分,对象声明对于单例模式的实现的理解使用。 后续若有新知识get到,那就随缘更新吧。

下一篇进阶篇的文章链接奉上:Kotlin学习小记之进阶篇(一) (以下是阿sweet的小牢骚,与本文内容毫无关联。) 我们什么都可以丢,但别丢了自己。

最新回复(0)