Kotlin学习小记-基础篇
这是一份大概的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学习小记之进阶篇(一)