【Android基础】第一行代码-Kotlin语法学习笔记
因为书是实体书,所以很多内容复制了这篇:快速入门kotlin编程(精简但全面版)-CSDN博客
基本语法
变量
kotlin没有基本数据类型,使用对象类型 Int,Long,Short, Float,Double,Boolean,Char,Byte。
不声明类型(kotlin存在类型推导机制)。使用val定义不变的变量(相当于final修饰),用var修饰可变变量
函数
fun 函数名(变量1:类型,变量2:类型):返回值类型
fun sum (a:Int,b:Int):Int{
return a+b
}
如果函数体只有一行代码的时候可以简写成
fun 函数名(变量1:类型,变量2:类型):返回值类型=函数体 (返回值类型也可以省略)
fun sum (a:Int,b:Int):Int= a+b
判断语句
if
if语句必须要有else,不然会报错
fun max(a: Int, b: Int): Int {
if (a > b)
return a
else
return b
}
if也可以放到return里面
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
when
适用于多个if-else if-else if-...-else 场景
fun getScore(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")
}
}
循环
while
和java完全一致
for-in
for (i in list){
//...
}
for (i in 0..10){
//...
}
类和对象
定义
-
创建类的时候选择 Kotlin Class/File 文件
-
输入类名
-
在类里面定义变量、方法等等
class Person {
var name = ""
var age = 0
fun pringInfo() {
println(name + "的年龄是" + age)
}
}
4. 调用的时候省去了new关键字
fun main() {
//去掉了new关键字
val person = Person()
person.name = "lyx"
person.age = 24
person.pringInfo()
}
继承
Kotlin中任何一个非抽象类默认都是不可以被继承的,相当于Java中给类声明了final 关键字。如果需要让一个类可以被继承,需要使用open关键字
open class Person {
var name = ""
var age = 0
fun pringInfo() {
println(name + "的年龄是" + age)
}
}
构造函数
主构造函数
特点:没有函数体,直接定义在类名的后面
每个类默认都会有一个不带参数的主构造函数
也可以显式地给它指明参数
class Student(val id: String, val grade: Int) : Person(name,age) {
//
}
如果主构造函数的逻辑需要特殊处理,Kotlin提供了init结构体,主构造的逻辑可在init中处理
open class Person(val name :String,val age :Int) {
init {
println("name is" + name)
println("age is" + age)
}
}
次构造函数
任何一个类只能有一个主构造函数,但是可以有多个次构造函数。
次构造函数的特点是:
-
有函数体
-
当一个类既有主构造函数又有次构造函数时,所有的次构造函数都必须调用主构造函数(包括间接调用)
-
是写在类里面
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) {
}
}
接口
接口的定义
interface Study {
fun study()
fun eat()
}
接口的实现
class Student : Person ,Study{
//Kotlin中使用override关键字来重写父类或者实现接口中的函数
override fun study() {
TODO("Not yet implemented")
}
override fun eat() {
TODO("Not yet implemented")
}
}
Kotlin支持接口方法的默认实现,方法有方法体默认实现,则继承类无需必须实现此方法
interface MyInterface {
fun foo() {
println("Interface default implementation")
}
}
class MyClass : MyInterface // 未重写 foo()
fun main() {
val obj = MyClass()
obj.foo() // 输出: "Interface default implementation"
}
如果实现类中重写了接口方法,则优先执行实现类的重写方法。
interface MyInterface {
fun foo() {
println("Interface default implementation")
}
}
class MyClass : MyInterface {
override fun foo() {
println("Class implementation")
}
}
fun main() {
val obj = MyClass()
obj.foo() // 输出: "Class implementation"
}
权限修饰符
| Java | kotlin | |
| public | 所有类 | 所有类(默认) |
| protected | 当前类,子类,同一包下的类 | 当前类,子类 |
| default | 同一包的类(默认) | x |
| private | 当前类 | 当前类 |
| internal | x | 同模块下的类 |
数据类
在创建的时候选择Data class
数据类则只处理数据相关,与Java Bean类似,通常需要实现其get,set,hashCode,equals,toString等方法
data class UserBean(var id: Int, var name: String)
若无data关键字,上述方法(hashCode,equals,toString)无法正常运行
kotlin支持嵌套类,当某个类只服务于外部类,且没有独立存在的意义时可以使用嵌套类。
data class ActionInfo (
val action: String?,
var dataList: List<DataItem>?
) : Serializable{
data class DataItem (var key: String, var value: Any?) : Serializable
}
单例类
在创建的时候选择Object
object Singleton {
fun test(){
println("===")
}
}
在使用的时候
fun main(){
Singleton.test()
}
Lambda
lambda是一小段可以作为参数传递的代码
集合的函数式API是用于入门Lambda编程的绝佳实例,所以先介绍Kotlin 集合的使用
//1.常规创建方式
val list1 =ArrayList<String>()
list1.add("a")
list1.add("b")
//2.listOf:不可变,只能查
val list2 =listOf<String>("a","b")
list2.add("c") //报错
//3.mutableListOf:可变
val list3=mutableListOf<String>("a","b")
list3.add("c")
//循环
for (value in list2) {
println(value)
}
//set的创建,与list类似,使用的是setOf()和mutableSetOf()
val set1=setOf<Int,String>(1 to "a",2 to "b")
//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")
}
格式
{ 参数名1: 参数类型, 参数名2:参数类型 -> 函数体 }
//最外层是大括号,如果有参数传入到Lambda表达式的话,还需要声明参数列表,列表结尾用->表示函数体的开始,函数体内可以任意编写代码,但不建议过长,函数体最后一行代码作为Lambda表达式的返回值
方法介绍
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 }
}
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()
空指针判断
如果有特殊用处,函数的入参可空的时候,使用?表示可空
fun main() {
study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
// 此时这里会报错
study.eat()
}
如果参数可为空的话,则此对象调用的方法必须要保证对象不为空,上面代码没有保证,则报错,修改如下
fun main() {
study(null)
}
// ? 表示参数可以为空,
fun study(study: Study?) {
if (study != null) {
study.eat()
}
}
-
?.
表示?前面的不为空,才会执行.后面的方法,
如果为空,就什么都不做
fun study(study: Study?) {
study?.eat()
}
-
?:
表示?前的不为空,才返回?前的值,否则返回?后的值
val c = a ?: b
fun getTextLength(text: String?) = text?.length ?: 0
-
!!
可以强行通过编译,但如果对象为空,会抛出空指针异常
fun study(study: Study?) {
study!!.eat()
}
let
fun study(study: Study?) {
// ?.保证了study不为空,才会执行let函数
study?.let {
it.eat() // it是study
it.drink()
}
}
全局变量判空
因为全局变量的值随时都有可能被其他线程所修改,所以做了判空处理也无法保证没有空指针风险
var str: String? = null
fun demo() {
//有问题
if (str != null) {
str.toUpperCase()
str.reversed()
}
}
fun demo1() {
//使用let规避风险
str?.let {
it.toUpperCase()
it.reversed()
}
}
内嵌表达式
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} 大")
}
函数参数默认值
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")
}
更多推荐



所有评论(0)