文章目录
一. 变量和函数
1. 变量
val 不可变变量;var 可变变量
Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型。
优先使用val
2. 函数
Java中方法的叫法更普遍一些,Kotlin中函数的叫法更普遍一些;二者为同一东西
- 标准写法
fun largerNumber(num1: Int, num2: Int): Int {
return max(num1, num2)
}
- 重要语法糖
当一个函数中只有一行代码时,Kotlin允许我们不必编写函数体,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可。
kotlin具有优秀的推导机制,不用再显式地声明返回值类型。
因此可以写成:
fun largerNumber(num1: Int, num2: Int) = max(num1, num2)
二. 程序的逻辑控制
1. if 语句
与Java相比,可以有返回值
fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) {
num1
} else {
num2
}
2. When 语句
格式:匹配值 -> {执行逻辑}
带有返回值
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
也可以进行类型匹配
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
3. For循环
- 区间
0…10 闭区间[0,10]
for (i in 0 until 10 step 2) [0,10) 步长2
降序区间 for (i in 10 downTo 1)
二. 面向对象编程
1. 继承与构造函数
- 在Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final关键字;要继承必须加上open关键字
- 构造函数:主构造函数和次构造函数
主构造函数:只能有一个,无函数体,直接定义在类名后面,如果需要逻辑写在init里面(一般不会这么操作的)
// person是无参主构造函数;也必须带括号
class Student(val sno: String, val grade: Int) : Person() {
init {
println("sno is " + sno)
println("grade is " + grade)
}
}
// 假设person构造函数带参数
open class Person(val name: String, val age: Int) {
...
}
// 注意此时student参数grade int不能带val
class Student(val sno: String, val grade: Int, name: String, age: Int) :
Person(name, age) {
...
}
次构造函数:可以有多个,有函数体,必须调用主构造函数
class Student(val sno: String, val grade: Int, name: String, age: Int) :
Person(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {}
constructor() : this("", 0) {}
}
//第一个次构造函数接收name和age参数,然后它又通过this关键字调用了主构造函数,并
//将sno和grade这两个参数赋值成初始值;
//第二个次构造函数不接收任何参数,它通过this关键字调用了我们刚才定义的第一个次构造
//函数,并将name和age参数也赋值成初始值
类中只有次构造函数,没有主构造函数
// 不需要括号;采用super
class Student : Person {
constructor(name: String, age: Int) : super(name, age) {
}
}
2. 接口 & 函数的可见性修饰符
冒号,允许对接口进行默认实现
3. 数据类与单例类
data class x {}
object {}
三. Lambda编程
四. 空指针异常
1. 可空类型系统
// 如果是Java会报错;Kotlin则不会
// Kotlin默认所有的参数和变量都不可为空,所以这里传入的Study参数也一定不会为空
// Kotlin将空指针异常的检查提前到了编译时期
fun doStudy(study: Study) {
study.readBooks()
study.doHomework()
}
?表示study可以为空
fun doStudy(study: Study?) {
if (study != null) {
study.readBooks()
study.doHomework()
}
}
2. 判空辅助工具
?. 就是当对象不为空时正常调用相应的方法,当对象为空时则什么都不做
?: 这个操作符的左右两边都接收一个表达式,如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
!! 的意思是这个参数如果为空,就抛出异常。
let函数处理全局变量判空
fun doStudy(study: Study?) {
study?.let {
it.readBooks()
it.doHomework()
}
}
五. Kotlin中的小魔术
1. 字符串内嵌
"hello, ${obj.name}. nice to meet you!"
println("Cellphone(brand=$brand, price=$price)")
2. 函数的参数默认值
fun printParams(num: Int = 100, str: String) {
println("num is $num , str is $str")
}
fun main() {
printParams(str = "world")
}
有了这个功能,因此不需要此构造函数。例子如下:
class Student(val sno: String, val grade: Int, name: String, age: Int) :
Person(name, age) {
constructor(name: String, age: Int) : this("", 0, name, age) {
}
constructor() : this("", 0) {
}
}
可以写成
class Student(val sno: String = "", val grade: Int = 0, name: String = "", age: Int = 0) :
Person(name, age) {
}
六. 泛型的引入写法
在 Kotlin 中,引入泛型的函数可以让你编写更通用和灵活的代码。下面是一些关于如何定义和使用泛型函数的基本示例:
1. 基本泛型函数定义
fun <T> printElement(element: T) {
println(element)
}
在这个示例中,<T>
是一个泛型类型参数,表示函数 printElement
可以接受任何类型的 element
。
2. 带有多个泛型类型参数的函数
fun <T, R> combineElements(first: T, second: R): String {
return "$first and $second"
}
这里,<T, R>
表示函数 combineElements
有两个泛型类型参数 T
和 R
,函数可以接受任意类型的 first
和 second
参数,并将它们合并成一个字符串。
3. 泛型函数与约束
你可以为泛型参数指定约束,以限制可以传入的类型:
fun <T : Comparable<T>> findMax(a: T, b: T): T {
return if (a > b) a else b
}
在这个示例中,T : Comparable<T>
表示 T
必须实现 Comparable<T>
接口,这样才能使用 >
运算符进行比较。
4. 泛型函数与上下文
如果你需要使用泛型函数与上下文相关的功能,可以这样做:
inline fun <reified T> isInstance(value: Any): Boolean {
return value is T
}
这里,reified
修饰符使得在函数体内可以使用 T
类型的信息,从而可以实现类型检查等功能。
5. 泛型函数在类中的使用
泛型函数也可以用在泛型类中:
class Box<T>(val value: T) {
fun getValue(): T {
return value
}
}
在这个示例中,Box
是一个泛型类,它有一个类型参数 T
,并且包含一个返回 T
类型的函数 getValue
。
通过这些示例,你可以看到 Kotlin 中泛型的强大灵活性,它使得你可以编写更加通用和可复用的代码。