注:本文章为个人学习记录,如有错误,欢迎留言指正。
目录
1. 变量
kotlin没有;结尾
1.1 变量声明
//不声明类型(kotlin存在类型推导机制)
val a = 1 //final修饰,先使用val,有需要可变,再改成var
var b = 2 //无final修饰
// 声明类型用“:”
var c: Int = 1
优先使用val
1.2 数据类型
kotlin没有基本数据类型,使用对象类型 Int,Long,Short, Float,Double,Boolean,Char,Byte
2. 函数
fun main() {
}
fun sum(a: Int, b: Int): Int {
return a + b
}
// 函数体只有一行代码:
fun sum(a: Int, b: Int): Int = a + b
// Kotlin存在类型推导,返回值类型也可省略
fun sum(a: Int, b: Int) = a + b
3. 判断语句
有if和when
3.1 if
if语句必须要有else,不然会报错
//返回最大值
fun max(a: Int, b: Int): Int {
if (a > b)
return a
else
return b
}
//if可以包含返回值,if语句的最后一行会作为返回值返回
fun max(a: Int, b: Int): Int {
return if (a > b)
a
else
b
}
//写成一行
fun max(a: Int, b: Int) = if (a > b) a else b
3.2 when语句
eg:
//使用if实现
// Kotlin中==等价于Java的equals, 比较的是对象里的内容,
// === 等价于Java的==,比较的为对象的引用。
fun getScore(n: String) = if (n == "A") "优秀"
else if (n == "B") "良好"
else "不好"
//使用when实现(when和if一样也可以有返回值)
fun getScore1(n: String) =
when (n) {
"A" -> "优秀"
"B" -> "良好"
else -> "不好"
}
when支持参数检查
fun checkType(num: Number) {
when (num) {
is Int -> println("Int")
is Double -> println("Double")
else -> println("others")
}
}
when里面也可以不填形参
fun getScore2(n: String) =
when {
n == "A" -> "优秀"
n == "B" -> "良好"
else -> "不好"
}
->后面也可以有很多行
fun getScore3(n: String) =
when {
n == "A" -> {
println("打印一下:$n")
"优秀"
}
n == "B" -> "良好"
else -> "不好"
}
4. 循环语句
有while和for-in。
while与java中的while没有区别,
for-in是对Java for-each的加强,
Kotlin舍弃了for-i的写法
4.1 while
和java一样
4.2 for-in
Java中的for-i在Kotlin中被舍弃
Java中的for-each被Kotlin加强变成了for-in
-
什么是区间
// 表示[0,10]区间 val range = 0..10 // 表示[0,10)区间 val range1 = 0 until 10
-
for-in的使用
for (i in 0..10) { println(i) //0 ~ 10 } for (i in 0 until 10) { println(i) //0 ~ 9 } for (i in 0 until 10 step 2) { println(i) //0,2,4,6,8 } for (i in 10 downTo 1) { println(i) //10 ~ 1 }
5. 类和对象
5.1 类的创建和对象的初始化
-
创建Person类
class Person {
var name = ""
var age = 0
fun pringInfo() {
println(name + "的年龄是" + age)
}
}
-
在main方法中声明一个Person对象并调用printInfo方法
fun main() {
//去掉了new关键字
val person = Person()
person.name = "lyx"
person.age = 24
person.pringInfo()
}
5.2 继承
Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final 关键字。
声明Student类继承Person,Kotlin中继承使用:,后接父类的构造
Person类为final不可被继承,因此需借助open关键字
class Student : Person() {
var id = ""
var grade = 0
fun study() {
println(name + "是一个学生")
}
}
5.3 构造函数
Kotlin将构造函数分 成了两种:主构造函数和次构造函数。
5.3.1 主构造函数
特点:没有函数体,直接定义在类名的后面
每个类默认都会有一个不带参数的主构造函数
class Student(val id: String, val grade: Int) : Person() {
}
也可以显式地给它指明参数
实例化的时候,必须传入构造函数中要求的所有参数
open class Person(val name :String,val age :Int) {
}
此时Student类就会报错,因为Person没有无参构造了
修改:
class Student( name :String, age :Int,val id: String, val grade: Int) : Person(name,age) {
}
init结构体
构造时需要进行特殊处理怎么办,Kotlin提供了init结构体,主构造的逻辑可在init
中处理
open class Person(val name :String,val age :Int) {
init {
println("name is" + name)
println("age is" + age)
}
}
5.3.2 次构造函数
任何一个类只能有一个主构造函数,但是可以有多个次构造函数
次构造写在{}里面
有函数体
当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
class Student(name: String, age: Int, val id: String, val grade: Int) : Person(name, age) {
// 三个参数
// this关键字调用了主构造函数,this里面写默认值
constructor(name: String, age: Int, id: String) : this("", 0, "", 0) {
}
// 无参构造
//this关键字调用刚才定义的第一个次构造函数
constructor() : this("", 0, "", 0) {
}
}
5.3.3 无主构造
次构造可以调用父类构造super进行初始化,
但是次构造的参数在其他地方无法引用,
class Student : Person {
// 次构造可以调用父类构造super进行初始化
constructor(name: String, age: Int, id: String) : super(name, age) {
}
fun study() {
//
// name,age可使用
println(name + "," + age + ",")
// 使用number则会报错,若number是主构造的参数则可引用
// println(number) 报红
}
}
6. 接口
6.1 接口定义
和java类似
interface Study {
fun study()
fun eat()
}
6.2 接口的实现
在后面加逗号
class Student : Person ,Study{
//Kotlin中使用override关键字来重写父类或者实现接口中的函数
override fun study() {
TODO("Not yet implemented")
}
override fun eat() {
TODO("Not yet implemented")
}
}
Kotlin支持接口方法的默认实现,
方法有方法体默认实现,则继承类无需必须实现此方法
interface Study {
fun study()
fun eat(){
println("eat")
}
}
7. 权限修饰符
Java | kotlin | |
---|---|---|
public | 所有类 | 所有类(默认) |
protected | 当前类,子类,同一包下的类 | 当前类,子类 |
default | 同一包的类(默认) | x |
private | 当前类 | 当前类 |
internal | x | 同模块下的类 |
8. 数据类和单例类
8.1 数据类
数据类则只处理数据相关,与Java Bean类似,通常需要实现其get
,set
,hashCode
,equals
,toString
等方法
一行代码即可
若无data
关键字,上述方法(hashCode
,equals
,toString
)无法正常运行
当一个类中没有任何代码时,还可以将尾部的大括号省略。
data class UserBean(var id: Int, var name: String)
8.2 单例类
创建单例类,创建类型选择“Object”
object Singleton {
fun test(){
println("===")
}
}
对应Java:
public final class Singleton {
@NotNull
public static final Sinfleton INSTANCE;
public final void test() {
String var1 = "===";
System.out.println(var1);
}
private Sinfleton() {
}
static {
Sinfleton var0 = new Sinfleton();
INSTANCE = var0;
}
}
使用:
fun main() {
Singleton.test()
}
9. Lambda
9.1 集合的创建和使用
fun main() {
//(1) List集合的创建
// 常规创建
val list = ArrayList<Int>()
list.add(1)
list.add(2)
// lisrOf:不可变,只能查
val list1 = listOf<Int>(1, 2, 3)
// list1.add(4) //报错
// mutableListOf:可变
val list2 = mutableListOf<Int>(1, 2, 3)
list2.add(4)
// 循环
for (value in list2) {
println(value)
}
//(2) Set集合与List类似, 只是使用的是setOf()和mutableSetOf()
val set = setOf<Int, String>(1 to "1", 2 to "2")
//(3) Map
val map1 = HashMap<Int, String>()
map1.put(1, "1")
map1.put(2, "2")
// 赋值
map1[2] = "222"
// 访问
println(map1[2])
println(map1.get(2))
// 不可变
val map2 = mapOf<Int, String>(1 to "1", 2 to "2")
// map2[2] = "222" //报错
// 可变
val map3 = mutableMapOf<Int, String>(1 to "1", 2 to "2")
map3[2] = "222"
// 循环
for ((key, value) in map3) {
println("$key:$value")
}
}
9.2 Lambda的使用
Lambda格式: { 参数名1: 参数类型, 参数名2:参数类型 -> 函数体 }
-
maxByOrNull():返回当前集合中...最大元素
-
map 映射:返回新集合,将集合中的元素映射成另一个值
-
filter过滤:返回新集合,将集合中的元素进行筛选
-
any:返回Boolean,集合中是否存在元素满足Lambda的条件,有则返回true,无则false
-
all:返回Boolean,集合中元素是否全部满足Lambda的条件,有则返回true,无则false
fun main() {
val list = listOf<String>("aa", "dededed", "ajd", "aa")
// 返回当前list中xx最大的元素
// (1)不使用maxByOrNull函数
var maxStr = ""
for (str in list) {
if (str.length > maxStr.length) {
maxStr = str
}
}
println("list中最大的str:" + maxStr)
// (2)使用maxByOrNull函数
// maxByOrNull或者maxBy是一个普通的方法,参数是Lambda参数
var lambda = { str: String -> str.length }
var maxString = list.maxByOrNull(lambda)
println("list中最大的str:" + maxString)
// 直接当成参数传递
var maxString1 = list.maxByOrNull({ str: String -> str.length })
// 如果lambda是方法的最后一个参数,参数可以提出来
var maxString2 = list.maxByOrNull() { str: String -> str.length }
// 如果只有一个参数,且是lambda参数,可以去掉方法的()
var maxString3 = list.maxByOrNull { str: String -> str.length }
// 有类型推导机制,也可以去掉参数类型
var maxStrinf4 = list.maxByOrNull { str -> str.length }
// 如果lambda只有一个参数,可以用it代替
var maxString5 = list.maxByOrNull { it.length }
// map映射(将集合中的每个元素都映射成一个另外的值)
var newList1 = list.map { it.toUpperCase() }
// filter过滤
var newList2 = list.filter { it.length > 5 }
// any 判断是否存在满足条件的元素
var isAny = list.any { it.length > 5 }
// all 判断是否全部满足条件
var isAll = list.all { it.length > 0 }
}
10. Java函数式接口的使用
kotlin调用Java的方法,如果方法只接收一个Java单继承方法接口参数,可以使用函数式接口。
单继承方法接口:就是接口中只有一个方法,比如Runnable接口:
public interface Runnable {
void run();
}
在Java中启动一个线程:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("test");
}
}).start();
在kotlin中:
// Kotlin摒弃了new,若想声明匿名内部类,必须使用object
Thread(object :Runnable{
override fun run() {
print("aaa")
}
}).start()
// Runnable类中只有一个待实现方法,即使这里没有显式地重写run()方法,Kotlin也能自动明白Runnable后面的Lambda 表达式就是要在run()方法中实现的内容
Thread(Runnable {
print("aaa")
}).start()
// 如果一个Java方法的参数列表中有且仅有一个Java单抽象方法接口参数,可以将接口名进行省略
Thread({
print("aaa")
}).start()
// Thread只需一个参数,可省略()
Thread {
print("aaa")
}.start()
// 与上类似的,click也使用上述方法
// button.setOnClickListener { println("test") }
11. 空指针检查机制
Kotlin把空指针异常的检查提前到了编译期,若空指针则编译期就会崩溃,避免在运行期出现问题
fun main() {
// study(null)// 编译期就会报错
}
fun study(study: Study) {
study.eat()
}
有特殊的需求,可能需要传递null参数,用?表示可以为空
fun main() {
study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
// 此时这里会报错
study.eat()
}
如果参数可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下
fun main() {
study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
if (study != null) {
study.eat()
}
}
11.1 判空辅助工具
-
?.
表示?前面的不为空,才会执行.后面的方法,
如果为空,就什么都不做
fun study(study: Study?) { study?.eat() }
-
?:
表示?前的不为空,才返回?前的值,否则返回?后的值
val c = a ?: b fun getTextLength(text: String?) = text?.length ?: 0
-
!!
想要强行通过编译
fun study(study: Study?) { study!!.eat() }
11.2 let函数
fun study(study: Study?) {
// ?.保证了study不为空,才会执行let函数
study?.let {
it.eat() // it是study
it.drink()
}
}
11.3 全局变量判空
全局变量即使做了判空,但是很可能被其他地方修改,还是不能保证没有空指针
var str: String? = null
fun demo() {
//有问题
if (str != null) {
str.toUpperCase()
str.reversed()
}
}
fun demo1() {
//使用let规避风险
str?.let {
it.toUpperCase()
it.reversed()
}
}
12. 内嵌表达式
在Java中使用的是+连接,kotlin中用$
fun main() {
var name = "lyx"
var age = 24
println("姓名:$name,年龄:$age")
// 复杂的: ${}
var a = 2
var b = 3
println("a和b比较,${if (a > b) a else b} 大")
}
13. 函数的参数的默认值
给函数设定参数默认值,在很大程度上能够替代次构造函数
fun main() {
// 正常传参
myFun(1, "lisa")
// 只传第一个,第二个参数有默认
myFun(2)
// 如果第一个参数有默认值,此时会报错,因为参数按照顺序放的
// myFun1("lyx") //认为传入的是Int
// kotlin使用键值对传参,不必按照参数定义的顺序来传参
myFun1(name = "lyx")
}
// 第二个参数有默认值
fun myFun(id: Int, name: String = "nana") {
println("$id:$name")
}
// 第一个参数有默认值
fun myFun1(id: Int = 4, name: String) {
println("$id:$name")
}
之前的次构造函数(三个参数的),可以和主构造合并,只需要把不需要的参数加上默认值即可:
// 不使用默认参数
class Student1(name: String, age: Int, val number: String, val grade: Int) : Person(name, age) {
constructor(name: String, age: Int, number: String) : this(name, age, number, 0) {
}
}
// 使用默认参数
class Student2(name: String, age: Int, val number: String, val grade: Int = 0) : Person(name, age) {
}