持续更新~~~~
1 Kotlin快速入门
01 运行kotlin项目
??可以百度kotlin代码在线运行网站。
??可以在Android studio 新建kotlin文件直接运行(前提是在Android studio建立的kotlin版本项目下)
2 编程之本:变量和函数
01 变量
??只允许在变量前声明两种关键字:val和var。
- val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量。
- var(variable的简写)用来声明一个可变的变量,这种变量在初始赋值之后仍然可以再被重新赋值,对应Java中的非final变量。
??Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型。 显示声明变量类型
val a:Int = 10
Java基本数据类型 | Kotlin对象数据类型 | 数据类型说明 |
---|
int | Int | 整型 | long | Long | 长整型 | short | Short | 短整型 | float | Float | 单精度浮点型 | double | Double | 双精度浮点型 | boolean | Boolean | 布尔型 | char | Char | 字符型 | byte | Byte | 字节型 |
02函数
fun methodName(param1: Int, param2: Int): Int {
return 0
}
??参数的声明格式是“参数名: 参数类型”,其中参数名也是可以随便定义的,这一点和函数名类似。如果不想接收任何参数,那么写一对空括号就可以了。 ??参数括号后面的那部分是可选的,用于声明该函数会返回什么类型的数据,上述示例就表示该函数会返回一个Int类型的数据。如果你的函数不需要返回任何数据,这部分可以直接不写。 例子:
fun largerNumber(num1 : Int,num2 : Int){
return max(num1,num2)
}
fun main() {
val a = 37
val b = 21
val value = largerNumber(a,b)
println(value)
}
3 程序逻辑控制
01 if语句
fun largerNumber(num1 : Int,num2 : Int){
var value = 0
if (num1 > num2) {
value = num1
} else {
value = num2
}
return value
}
简化:
fun largerNumber(num1: Int, num2: Int): Int {
return if (num1 > num2) {
num1
} else {
num2
}
}
语法糖简化(当一个函数只有一行代码时,可以省略函数体部分,直接将这一行代码使用等号串连在函数定义的尾部。)
fun largerNumber(num1: Int, num2: Int)
=
if (num1 > num2) {
num1
} else {
num2
}
语法糖再简化
fun largerNumber(num1: Int, num2: Int) = if (num1 > num2) num1 else num2
02 when语句
有点类似java中的switch
fun getScore(name: String) = when (name) {
"Tom" -> 86
"Jim" -> 77
"Jack" -> 95
"Lily" -> 100
else -> 0
}
格式: 匹配值 -> { 执行逻辑 } (当执行逻辑只有一句话时,可以省略{})
除了精确匹配之外,when语句还允许进行类型匹配
fun checkNumber(num: Number) {
when (num) {
is Int -> println("number is Int")
is Double -> println("number is Double")
else -> println("number not support")
}
}
03 循环语句
val range = 0..10
for (i in range){
println(i)
}
??其中 0…10相当于[0,10] 0 until 10 相当于[0,10) 10 downTo 0 相当于 [10,0]
4 面向对象编程
01 类与对象
定义一个类:
class Person {
var name = ""
var age = 0
fun eat(){
println(name + " is eating. He is " + age + " years old")
}
}
new 对象
fun main(){
var p = Person()
p.name = "lee"
p.age = 18
p.eat()
}
02 继承和构造函数
令Person类可以被继承
open class Person {
...
}
Student继承Person
1.
class Student : Person() {
var sno = ""
var grade = 0
override fun toString(): String {
return "Student(sno='$sno', grade=$grade)"
}
}
var stu = Student()
stu.age = 18
stu.name = "lee"
stu.grade = 4
stu.sno = "2017051313"
2.主构造函数的特点是没有函数体,直接定义在类名的后面即可
class Student(val sno: String, val grade: Int) : Person() {
}
var stu = Student("2017051313",4)
当父类的主构造函数不为空时
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) {
}
}
val student1 = Student()
val student2 = Student("Jack", 19)
val student3 = Student("a123", 5, "Jack", 19)
03 接口
子类继承父类、实现接口
open class Person(val name:String, val age:Int) {
}
interface Study {
fun readBooks()
fun doHomework()
}
class Student(name:String,age: Int):Person(name,age),Study{
override fun readBooks(){
println(name + " is readBooks")
}
override fun doHomework() {
println(name + " is doHomework")
}
}
实例化
fun main() {
var stu = Student("lee",18)
stu.doHomework()
stu.readBooks()
doStudy(stu)
}
fun doStudy(study: Study) {
study.readBooks()
study.doHomework()
}
结果: ??Kotlin还增加了一个额外的功能:允许对接口中定义的函数进行默认实现(在实现类中,可以不实现该函数了)。
函数的可见性修饰符
修饰符 | Java | Kotlin |
---|
public | 所有类可见 | 所有类可见(默认) | private | 当前类可见 | 当前类可见 | protected | 当前类、子类、同一包路径下的类可见 | 当前类、子类可见 | default | 同一包路径下的类可见(默认) | 无 | internal | 无 | 同一模块中的类可见 |
04 数据类与单例类
??数据类通常需要重写equals()、hashCode()、toString()这几个方法。 其中,
- equals()方法用于判断两个数据类是否相等。
- hashCode()方法作为equals()的配套方法,也需要一起重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。
- toString()方法用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址。
??根据实际需求编写equal和hashcode函数的内容.
java中需要重写方法,kotlin中只需要"data"关键字 数据类Cellphone
data class Cellphone(val brand: String, val price: Double)
调用
fun main() {
var cellphone = Cellphone("OPPO",3000.0)
println(cellphone)
}
单例类 ??只需要将class改成object即可
object Singleton {
fun singletonTest(){
println("singletonTest is called")
}
}
调用
Singleton.singletonTest()
5 Lambda编程
??传统意义上的集合主要就是List和Set,再广泛一点的话,像Map这样的键值对数据结构也可以包含进来。 List、Set和Map在Java中都是接口.
- List的主要实现类是ArrayList和LinkedList
- Set的主要实现类是HashSet
- Map的主要实现类是HashMap
01 集合的创建与遍历
??对于list,有两种生成方法,其中listOf生成的list集合,内容不可变
fun main() {
val list = listOf<String>("apple","banana","orange")
val mutableList = mutableListOf<String>("apple","banana","orange")
mutableList.add("grape")
for (fruit in mutableList){
println(fruit)
}
}
??对于set,有两种生成方法,跟list类似,只是改成setOf和mutableSetOf.并且set不能放重复元素,放,也只会保存一个
??Kotlin中并不建议使用put()和get()方法来对Map进行添加和读取数据操作,而是更加推荐使用一种类似于数组下标的语法结构
val map = HashMap<String, Int>()
map["Apple"] = 1
map["Banana"] = 2
map["Orange"] = 3
map["Pear"] = 4
map["Grape"] = 5
val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)
for ((fruit, number) in map) {
println("fruit is " + fruit + ", number is " + number)
}
02 集合的函数式API
总结: ??在大括号内填写条件.
val list = listOf<String>("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val maxLengthFruit = list.maxByOrNull { it.length }
println("max length fruit is " + maxLengthFruit)
??Lambda表达式的语法结构: ??{参数名1: 参数类型, 参数名2: 参数类型 -> 函数体} 首先最外层是一对大括号, 如果有参数传入到Lambda表达式中的话,我们还需要声明参数列表, 参数列表的结尾使用一个->符号,表示参数列表的结束以及函数体的开始, 函数体中可以编写任意行代码(虽然不建议编写太长的代码),并且最后一行代码会自动作为Lambda表达式的返回值。
??maxBy就是一个普通的函数而已,只不过它接收的是一个Lambda类型的参数,并且会在遍历集合时将每次遍历的值作为参数传递给Lambda表达式。 ??maxBy函数的工作原理是根据我们传入的条件来遍历集合,从而找到该条件下的最大值
val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxByOrNull(lambda)
?简化
val maxLengthFruit = list.maxByOrNull({ fruit: String -> fruit.length })
?1 .Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面
val maxLengthFruit = list.maxByOrNull(){ fruit: String -> fruit.length }
?2. 如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略:
val maxLengthFruit = list.maxByOrNull{ fruit: String -> fruit.length }
?3. Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型
val maxLengthFruit = list.maxByOrNull{ fruit -> fruit.length }
?4. 当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替
val maxLengthFruit = list.maxByOrNull { it.length }
??集合中的map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。 ??filter函数是用来过滤集合中的数据的,它可以单独使用,也可以配合刚才的map函数一起使用。
val list = listOf<String>("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val newList = list.filter { it.length <= 5 }.map { it.toUpperCase() }
for (fruit in newList){
println(fruit)
}
??any函数用于判断集合中是否至少存在一个元素满足指定条件,all函数用于判断集合中是否所有元素都满足指定条件。
val list = listOf<String>("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon")
val anyResult = list.any { it.length <= 5 }
val allResult = list.all { it.length <= 5 }
println("anyResult is " + anyResult + ", allResult is " + allResult)
03 Java函数式API的使用
总结: ??对作为参数的 单抽象方法接口(参数) 进行简化 ??Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。 格式:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread is running");
}
}).start();
简化:
- kotlin写法
Thread(object :Runnable{
override fun run() {
println("run")
}
}).start()
- 因为Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,Kotlin也能自动明白Runnable后面的Lambda表达式就是要在run()方法中实现的内容。
Thread(Runnable {
println("run")
}).start()
- 继续省略,kotlin知道参数是Runnable,省略Runnable.移动括号,省略括号.
Thread{
println("run")
}.start()
实例:
btn.setOnClickListener{
println("click")
}
6 空指针检查
??Android系统上崩溃率最高的异常类型就是空指针异常(NullPointerException)。
fun doStudy(study: Study) {
study.readBooks()
study.doHomework()
}
??在kotlin中,如果调用方法传入null值,会报错
01 可空类型系统
??只需在类后面添加"?",并进行判空即可
fun doStudy(study: Study?) {
if (study != null) {
study.readBooks()
study.doHomework()
}
}
02 判空辅助工具
??
"?."操作符.
当对象不为空时正常调用相应的方法, 当对象为空时则什么都不做。
fun doStudy(study: Study?) {
study?.readBooks()
study?.doHomework()
}
"?:"操作符
操作符的左右两边都接收一个表达式 如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。
val c = if (a ! = null) {
a
} else {
b
}
简化:
val c = a ?: b
非空断言(确信不会为空,自己负责后果)
非空断言
fun printUpperCase() {
val upperCase = content!!.toUpperCase()
println(upperCase)
}
let函数
??这个函数提供了函数式API的编程接口,并将原始调用对象作为参数传递到Lambda表达式中。
obj.let { obj2 ->
}
具体实例:
fun doStudy(study: Study?) {
study?.readBooks()
study?.doHomework()
}
fun doStudy(study: Study?) {
study?.let { stu ->
stu.readBooks()
stu.doHomework()
}
}
let函数是可以处理全局变量的判空问题的,而if判断语句则无法做到这一点。
全局变量,其他线程可能对study变量进行修改,导致空指针风险
7 Kotlin中的小魔术
01 字符串内嵌表达式
格式:
" hello, ${object.name}"
实例:
open class Person(val name:String, val age:Int) {
override fun toString(): String {
return "Person(name='$name', age=$age)"
}
}
02 默认值
fun printParams(num: Int, str: String = "hello") {
println("num is $num , str is $str")
}
fun main() {
printParams(123)
}
若默认值在前边,则使用键值对传值
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) {
}
8
|