声明:内容来自 HenCode 码上开学 的学习笔记
真心推荐,视频和文章都超级赞,非常感谢 🙏
另 附 Kotlin 学习官方文档
变量
变量声明: var关键字 变量名 :冒号 类型 结尾没有分号(对,Kotlin 里面不需要分号)
val
是 Kotlin 在 Java 的「变量」类型之外,又增加的一种变量类型:只读变量。它只能赋值一次,不能修改。而 var 是一种可读可写变量。
var
是 variable 的缩写,val
是 value 的缩写。
Kotlin 里面,变量没有初始值,如果声明的时候不赋值就会报错,可以用?
解除非空限制
所有的变量默认都是不允许为空的,如果你给它赋值 null,就会报错,
var name1: String // 👈这样写会报错,变量没有初始化
var name2: String = null // 👈这样写会报错,变量不能赋值null
var name3: String? = null //👈 正常运行 加?表示该变量是可空类型
name3.length //「👈这样写会报错 可空类型的变量,Kotlin 不允许使用,,,Only safe (?.) or non-null asserted (!!.) calls are allowed
name3?. length // 正常运行
Kotlin 空安全设计,记住,所谓「可空不可空」,关注的全都是使用的时候,即「这个变量在使用时是否可能为空」。
变量延迟初始化
关键字lateinit
修饰变量,告诉编译器我没法第一时间就初始化,但我肯定会在使用它之前完成初始化的。
类型推断, 就是在代码里不用写变量类型,编译器在编译的时候会帮你补上
var name: String = "Mike"
var name = "Mike" //可以省略变量类型String
静态属性和函数
object
Kotlin 里的 object
——首字母小写的,不是大写,Java 里的 Object
在 Kotlin 里不用了。
Java 中的 Object
在 Kotlin 中变成了 Any
,和 Object 作用一样:作为所有类的基类。
而 object 不是类,像 class 一样在 Kotlin 中属于关键字.
object 的意思是,创建一个类,并且创建一个这个类的对象。可以直接理解为单例。
Java 中new
用来创建一个匿名类的对象
Kotlin 中object:
也可以用来创建匿名类的对象
companion object
用 object
修饰的对象中变量和函数都是静态的,如果只想让类中的一部分函数和变量是静态的,那么可以在类中嵌套的对象可以用companion
修饰
top-level property / function 声明
除了静态函数这种简便的调用方式,Kotlin 还有更方便的东西:「top-level declaration 顶层声明」。其实就是把属性和函数的声明不写在 class 里面,
package com.hencoder.plus
// 👇 属于 package,不在 class/object 内
fun topLevelFuncion() {
}
这样写的属性和函数,不属于任何 class,而是直接属于 package,它和静态变量、静态函数一样是全局的,但用起来更方便:你在其它地方用的时候,就连类名都不用写
在实际使用中,在object、companion object
和 top-level
中该选择哪一个呢?简单来说按照下面这两个原则判断:
如果想写工具类的功能,直接创建文件,写 top-level「顶层」函数。
如果需要继承别的类或者实现接口,就用 object 或 companion object。
常量
Kotlin 中声明常量用关键字const
Kotlin 的常量必须声明在对象(包括伴生对象)或者「top-level 顶层」中,因为常量是静态的。
Kotlin 中只有基本类型和 String 类型可以声明成常量. 原因是 Kotlin 中的常量指的是 「compile-time constant 编译时常量」,它的意思是「编译器在编译的时候就知道这个东西在每个调用处的实际值」,因此可以在编译时直接把这个值硬编码到代码里使用的地方。
而非基本和 String 类型的变量,可以通过调用对象的方法或变量改变对象内部的值,这样这个变量就不是常量了。
函数
函数声明:fun关键字 方法名(参数..) 冒号 返回值类型{ 函数体 }
如果没有返回值 可以用 Unit ,也可以直接省略。 如果函数体只有一行代码可以直接用=不需要用{}
fun sum(a: Int, b: Int) = a + b //返回值类型也可以自动推断
//完全一样的两个函数
fun sum(a: Int, b: Int): Int {
return a + b
}
// 参数有默认值的函数
fun sum1(a: Int = 0, b: Int = 0): Int {
return a + b
}
Kotlin 函数参数默认是 val 类型,所以参数前不需要写 val 关键字,Kotlin 里这样设计的原因是保证了参数不会被修改,而 Java 的参数可修改(默认没 final 修饰)会增加出错的概率。
本地函数(嵌套函数)
类型
基本类型:数字(Byte、Short、Int、Long、Float、Double)、字符(Char)、布尔值(Boolean)、数组(Array)与字符串(String)
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"
在Kotlin中,较小类型不是较大类型的字类型,所以不能显式类型转换。
var b : Byte = 1
var number: Int = b// 👈错误,无法进行显式转换
var number: Int = b.toInt() // 正常运行
字符串
当字符串较多的时候,Java给出的解决方案是String.format
Kotlin 中,用$
加参数,不仅可以跟变量,还可以跟表达式,但表达式是一个整体,需要用{}
包起来。
trimMargin()
函数可以去除每行前面的空格
val text = """
👇
|Hi world!
|My name is kotlin.
""".trimMargin()
println(text)
注意:|
符号为默认的边界前缀,前面只能有空格,否则不会生效
输出时|
符号以及它前面的空格都会被删除
边界前缀还可以使用其他字符,比如 trimMargin("/")
,只不过上方的代码使用的是参数默认值的调用方式
数组和集合
Kotlin 和 Java 一样有三种集合类型:List、Set 和 Map,它们的含义分别如下:
List
以固定顺序存储一组元素,元素可以重复。
Set
存储一组互不相等的元素,通常没有固定顺序。
Map
存储 键-值 对的数据集合,键互不相等,但不同的键可以对应相同的值。
三种集合创建可变和不可变的例子:
listOf()
创建不可变的List
,mutableListOf()
创建可变的List
。
setOf()
创建不可变的Set
,mutableSetOf()
创建可变的Set
。
mapOf()
创建不可变的Map
,mutableMapOf()
创建可变的Map
。
可以看到,有 mutable前缀
的函数创建的是可变的集合,没有 mutbale 前缀
的创建的是不可变的集合,不过不可变的可以通过 toMutable*()
系函数转换成可变的集合:
val strList = listOf("a", "b", "c")
👇
strList.toMutableList()
val strSet = setOf("a", "b", "c")
👇
strSet.toMutableSet()
val map = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 3)
👇
map.toMutableMap()
注意:toMutable*() 返回的是一个新建的集合,原有的集合还是不可变的,所以只能对函数返回的集合修改。
Sequence
Kotlin 还引入了一个新的容器类型 Sequence,和 Iterable 一样用来遍历一组数据并可以对每个元素进行特定的处理.
类和对象
Kotlin 的类默认是 public 的,类的继承和实现都用:
,构造函数用关键字constructor
和其他函数fun进行区分。 Kotlin 中关键字override函数的可见性继承自父类
class MainActivity constructor()
类的主构造器
class User constructor(name: String) {
// 👇 这里与构造器中的 name 是同一个
var name: String = name
}
kotlin中一个类最多能有一个主构造器(可以没有),次构造器的个数没有限制。
java中一个类最多能有一个空构造函数(可以没有)。。是不是感觉很熟悉 哈哈哈
主构造器中的参数除了可以用作类的属性,还可以在init
代码块中使用,init
代码块是紧跟在主构造器之后执行的,因为主构造器没有带马蹄,init
代码块就充当类主构造器代码体的功能。
如果在主构造器的参数声明时加上 var 或者 val,就等价于在类中创建了该名称的属性(property),并且初始值就是主构造器中该参数的值。
如果类中有主构造器,那么次构造器要通过this
关键字调用主构造器,可以直接调用也可通过其他构造器间接调用,不管怎样,必须调用,否则会报错。
class User constructor(var name: String) {
// 👇 👇 直接调用主构造器
constructor(name: String, id: Int) : this(name) {
}
// 👇 通过上一个次构造器,间接调用主构造器
constructor(name: String, id: Int, age: Int) : this(name, id) {
}
}
通常情况下,主构造器中的constructor
关键字是可以省略的,但是,当主构造器使用 「可见修饰符」或者「注解」的时候是不可以省略的
class User private constructor(name: String) {
// 👆 主构造器被修饰为私有的,外部就无法调用该构造器
}
类型判断与强转
Kotlin 中使用 is
关键字进行「类型判断」,不判断直接强制转换使用关键字as
,
如果强转类型错误程序会报异常用as?
来处理这种情况,如果转换失败则不调用,转换成功才调用。
网友评论