目录
1、构造函数
2、数据类 data class,
3、object 单例类,相当于java线程安全的懒加载
4、companion object 伴生对象,类似于包装静态值的一个区域块
5、解构
6、空安全
7、条件语句
8、集合
9 属性和支持属性
属性
支持属性
10 扩展函数和扩展属性
11. 作用域函数:let、apply、with、run、also
1、构造函数
每个类都有一个主构造函数:
class Person constructor(firstName: String) { /*...*/ }
主构造函数若没有访问修饰或注解则可以省略constructor关键字
class Person(firstName: String) { /*...*/ }
若有访问修饰符或注解,则不能省略constructor关键字
class Customer public @Inject constructor(name: String) { /*...*/ }
主构造函数不能有代码块,若要有代码块则放入 init 代码块中,init代码块按顺序执行(初始化块按在类体中出现的顺序执行,与属性初始化器交错进行。)
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints $name")
}
val secondProperty = "Second property: ${name.length}".also(::println)
init {
println("Second initializer block that prints ${name.length}")
}
}
First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5
次构造函数需带有constructor 关键字,并且必须直间或间接调用主构造,通过this 关键字,
class Person(val name: String) {
val children: MutableList<Person> = mutableListOf()
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
init 其实是主构造的一部分,所以顺序是 主-〉init-〉次
若没写主构造函数,则次构造函数调用主构造是隐式调用的
2、数据类 data class,
data class Person(val name: String) {
var age: Int = 0
}
- 主构造函数必须有一个参数
- 数据类会默认重写equals() 来比较内容是否想到,如A对象和B对象,name都是 “张三” 则相等
- 重写hashCode()
- 重写toString() 的话回打印类属性 如 :"User(name=John, age=42)".
- 支持解构
- 支持属性copy()
- 注意:上面的内容只与主构造声明的参数有关,即例子里面的name属性,而age会忽略(equals,hashcode、解构、copy)。
注:
- 构成相等使用
==
运算符,并调用equals()
来确定两个实例是否相等。 - 引用相等使用 === 运算符,以检查两个引用是否指向同一对象。
3、object 单例类,相当于java线程安全的懒加载
object Repository {}
4、companion object 伴生对象,类似于包装静态值的一个区域块
class Repository {
companion object {}
}
5、解构
val(a,b)= person("A","B") 即解构声明,即将类部分分别解析赋值得到a=“A”,b=“B”。
支持解构的,如 数据类,map,list,pair 等,
普通类自定义支持解构要写:
class Point(var x: Int, var y: Int) {
operator fun component1(): Int {
return x
}
operator fun component2(): Int {
return y
}
}
6、空安全
用问号标示变量是否可空,如 var a:String? =“abc”
若操作可空变量,需要用到的方式
- if判断
- 安全操作符 ?. 若为null 则返回空,则不调用后边的表达式
- 空合并操作符 ?: 若为不为null 则返回本身调用,为null 则返回右边的
- 非空断言 !! 明确告诉编译器,我确定它不为null,若为null 则抛空异常
- a?.let{} 结合let函数,若为null则不调用let
- as? 对象转换,若转换失败,及给null值
7、条件语句
判断语句 if..else.. 类似于java
when语句,类似于java 的 switch语句,写法略有不同。else 相当于 default
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
循环语句 for while do..while 类似于java。
在 Kotlin 中,if、when、for 和 while 均为表达式,它们有返回值
8、集合
List 有序重复 创建方式:listOf
MutableList 创建方式:mutableListOf 兼容java型的创建 ArrayList()
Set 无序不重复 创建方式:setOf
MutableList 创建方式 mutableSetOf 兼容java HashSet()
Map 创建方式:mapOf("one" to 1, "two" to 2)
MutableMap 创建方式:mutableMapOf("a" to 1, "b" to 2) 兼容java HashMap()
ArrayDeque(双端队列)创建方式:ArrayDeque()ArrayDeque(List)
集合的高阶函数
- map{it * 2} 操作每一个元素(it代表集合中的每个元素),返回新的集合
- filter { it % 2 == 0 } 过滤元素,只有元素满足表达式的,才保留,it代表集合中的每个元素),返回新的集合
- reduce{sum, element -> sum + element } 累计计算,常用于计算集合中元素的总和、乘积等聚合操作
- foldfold(1) { acc, element -> acc * element } 类似于reduce,但是可以指定初始值
- forEach { println(it) } 遍历,没有返回值
- groupBy { it.department } 分租 groupBy函数用于将集合中的元素根据一个键选择器(以 Lambda 表达式形式表示)分组,返回一个以键为索引,值为分组后的元素列表的映射(Map)
例子:
data class User(val name: String, val department: String)
val users = listOf(User("Alice", "HR"), User("Bob", "IT"), User("Charlie", "HR"))
val groupedUsers = users.groupBy { it.department }
println(groupedUsers)
// 输出 {HR=[User(name=Alice, department=HR), User(name=Charlie, department=HR)],IT=[User(name=Bob, department=IT)]}
9 属性和支持属性
属性
默认提供 get 和 set 访问. val 只有get 访问器, get和set可以自定义如:
class Person {
var name: String = ""
get() {
println("Getting name")
return field
}
set(value) {
println("Setting name to $value")
field = value
}
}
lateinit是 Kotlin 中的一个关键字,用于修饰非空类型的属性,它允许你延迟初始化这个属性。通常用于在类初始化时无法立即初始化某个属性,但可以保证在该属性真正被使用之前会被初始化的情况。例如,在依赖注入或者 Android 的视图绑定场景中,视图属性在onCreate方法执行之前是未初始化的,但在onCreate方法执行过程中会被初始化,这种情况下可以使用lateinit。 若检查延迟初始化的属性是否已经初始化,用 属性.isInitialized
支持属性
_users即为 users的支持属性,外部访问时只能访问,而不能修改(因为外部访问时,返回的是不可变的List)
private val _users = mutableListOf<User>()
val users: List<User>
get() = _users
10 扩展函数和扩展属性
扩展函数
fun User.getFormattedUserName(): String {}
扩展属性
val User.formattedUserName:String
get() { }
11. 作用域函数:let、apply、with、run、also
它们的唯一目的是在对象的上下文中执行代码块。当您在提供了 lambda 表达式的对象上调用这样的函数时,它会形成一个临时作用域。在这个作用域中,您可以访问没有其名称的对象.
这些函数都执行相同的操作:在对象上执行代码块。不同的是这个对象在块内是如何变得可用的,以及整个表达式的结果是什么。
let函数
对象本身,it引用。返回值是let
块中最后一行表达式的值。
val text = "Hello, World!"
val length = text.let { it.length }
println(length)
//text对象调用let函数,在let块内部通过it引用text,直接返回text的长度。
run函数
对象本身,this引用(可省略),返回值是run
块中最后一行表达式的值。
data class Person(var name: String, var age: Int)
val person = Person("Alice", 30).run {
name = "Bob"
age += 5
this
}
println("Name: ${person.name}, Age: ${person.age}")
//这里Person对象调用run函数,在run块内部通过this引用Person对象,
//修改了name和age属性,最后返回修改后的Person对象本身。
with
函数
默认引用是入参对象,this
来引用这个参数。返回值是with
块中最后一行表达式的值。
val person = Person("Charlie", 25)
with(person) {
println("Name: $name, Age: $age")
}
//在这个例子中,with函数以person为参数,在with块内部通过this(也就是person)
//来访问name和age属性,这里不需要返回值,只是对person对象进行了信息打印操作。
apply
函数
对象本身,this引用,返回操作过后的当前对象
val person = Person("David", 35).apply {
name = "Eve"
age -= 5
}
println("Name: ${person.name}, Age: ${person.age}")
//这里Person对象调用apply函数,在apply块内部通过this引用Person对象,
//修改了name和age属性,最后返回修改后的Person对象本身。
also
函数
对象本身,it 引用,返回原始对象 (注意,它的设计意图是对对象额外操作,不是改变其本身)
val numbers = listOf(4, 5, 6).also {
println("Original list: $it")
}
println("Numbers: $numbers")
//在这个例子中,listOf(4, 5, 6)对象调用also函数,在also块内部通过
//it引用这个对象并打印它,最后also函数返回原始的list对象,并且可以再次打印这个对象。
函数 | 引用对象 | 引用字段 | 返回值 |
---|---|---|---|
let | 调用该函数的对象 | it | 最后一个表达式的值 |
run | 调用该函数的对象 | this | 最后一个表达式的值 |
with | 传入的对象 | this | 最后一个表达式的值 |
apply | 调用该函数的对象 | this | 经过配置后的对象本身 |
also | 调用该函数的对象 | it | 原始对象本身 |