【第一行代码学习笔记】第二章 Kotlin入门

第2章 Kotlin快速入门

  • 编译型语言:编译器会将源代码一次性编译成计算机可识别的二进制文件(C/C++);
  • 解释型语言:在程序运行时,解释器回一行一行读取源代码,然后实时地将这些源代码解释成二进制数据后再执行,效率稍差(Python/JavaScript);

Java虽需要编译,但其实是解释型语言。因为Java编译后生成的是class文件,再交由Java虚拟机来解释之。Kotlin和Java都可以生成class文件。

2.1 变量和函数

2.1.1 变量

变量前只允许声明两种关键字:

  • val:value,不可变变量;
  • var:variable,可变变量

Tips:永远优先使用val来声明一个变量。当val无法满足需求时再换成var。这样的程序会更加见状、也更符合高质量的编码规范。

2.1.2 函数
  • if函数:Kotlin中的if函数允许有返回值。例如下面这段代码
    fun largeNumber(a: Int, b: Int): Int = if (a>b) a else b
  • when函数:就类似下面这种
        fun checkNumber(num: Number) = when (num){
        is Int -> println("The number is an Int.")
        is Double -> println("The number is a Double.")
        else -> println("fuck u.")
    }   

还有另一种写法:

    fun getScore(name: String) = when {
            name=="nayufeng" -> 100
            name=="liuyuhe" -> 101
            name.startsWith("he") -> 0 // 表示所有he开头的名字,分数都是0分
            else -> 99
        }

` for函数:

for (i in 0..10){
    println(i)
} // 闭区间

for (i in 0 until 10 step 2){
    println(i)
} // 左闭右开

for (i in 10 downTo 1){
    println(i)
} // 倒序
2.1.3 面向对象编程:类与对象

在Kotlin中,任何一个非抽象类默认都是不可被继承的。想让一个类继承另一个类,必须再类前加上open关键字才可以:

open class Person {
    var name = ""
    var age = 0

    fun eat(){
        println(name + "is eating. He is " + age + " years old.")
    }
}

Kotlin中继承的关键字是一个冒号:

class Student: Person( ) {
    var sno = ""
    var grade = 0
}
  • 主构造函数:
    主构造函数标准定义格式:
class 类名 constructor( 构造函数参数 ){
	//类成员
}

如果主构造函数前没有修饰词(private, protected, internal, public)并且没有注解,那么可以省略constructor关键词:

/*
    省略 constructor 关键字的主构造函数
    省略 constructor 前提 :
        ① 主构造函数没有可见性修饰符 , 如 private , public , protected , internal (下面有详细jie'shao)
        ② 主构造函数没有注解
 */
class Student (name : String, age : Int){
}

继承时的Person( ) 中的这个括号意思就是调用Person类的主构造函数。当其中没有参数时是要加一对空括号就可以了;但是如果Person类需要传入参数时:

open class Person(val name: String, val age: Int) {
    ...
}

此时的Student类在继承Person类时就必须在括号中同时传入name和age这两个参数:

class Student(val sno: String, val grade: Int, name: String, age: Int) :
            Person(name, age) {
            ...
}

注意这里name和age参数前面不用加任何val或者var关键字。

  • 次构造函数
    基本上不会用到次构造函数。Kotlin提供了给函数设定参数默认值的功能,基本上可以替代次构造函数的作用。为了知识结构的完整性,还是要学一下次构造函数的。

Kotlin规定,当一个类既有主构造函数又有次构造函数时,所有次构造函数都必须调用主构造函数(包括间接调用)。

类中也可以只有次构造函数,没有主构造函数,但是很少见。当一个类中没有显式地定义主构造函数且定义了次构造函数时,它就是没有主构造函数的,例如:

class Student : Person{
    constructor(name:String, age:Int) : super(name, age){
    }
}

这里的super关键字用来调用父类的构造函数。

2.1.4 接口

以下代码是一个Study接口:

interface Study {
    fun readBooks()
    fun doHomework()
}

接下来由Student来实现Study接口:

class Student(name:String, age:Int): Person(name, age), Study {
    override fun readBooks() {
        println(name + "is reading.")
    }

    override fun doHomework() {
        println(name + "is doing homework.")
    }
}

如果在定义接口时,给函数加上函数体,那么这个函数就有了**“默认实现”**,在实现接口时就不强制实现这个有函数体的接口了。

Kotlin中的修饰符:publicprivateprotectedinternal。直接定义在fun关键字前面即可。

  • public:只对当前类内部可见;
  • public:对所有类可见。Kotlin中不加修饰符默认是public的;
  • protected:只对当前类和子类可见;
  • internal:只对同一模块中的类可见。
2.1.5 数据类和单例类
  • 数据类:专门用来存储数据的类。数据类的属性通常是不可变的,而普通类的属性可能是可变的。
    实现方法:在类之前加一个data关键字即可;
  • 单例类:单例类在全局最多只能拥有一个实例,这样可以避免创建重复的对象。
    实现方法:把class关键字改成object即可。

2.2 Lambda编程

2.2.1 集合的创建和遍历
  • 三种数据格式:ListSetMap
  • 初始化方法分别为listOf("Apple", "Banana")setOf("Apple", "Banana")mapOf("Apple" to 1, "Banana" to 2)
2.2.2 集合的函数式API

Lambda:一小段可以作为参数传递的代码;
Lambda表达式的语法结构:

{参数名1:参数类型,参数名2:参数类型 -> 函数体}

Lambda表达式可以有很多规则简化:

  1. 当Lambda参数是函数的最后一个参数时,可以将其移到函数括号的外面;
    val maxLengthFruit = list.maxBy( ) {fruit: String -> fruit.length}
    
  2. 如果Lambda参数是函数的唯一一个参数,还可以将函数的括号省略;
    val maxLengthFruit = list.maxBy {fruit: String -> fruit.length}
    
  3. 当Lambda表达式只有一个参数时,也不必声明参数名,而是可以用it关键字来代替。
    val maxLengthFruit = list.maxBy {it.length}
    
    除了maxBy这个函数之外,还有如下几个函数式API:
  • map:将集合中的每个元素都映射成另一个值,映射规则在lambda表达式中指定,最终生成一个新的集合。例如下列代码就将list中的所有元素变成大写:
	fun main() {
    val list = listOf("nayufeng", "wangruike", "ningmengcha")
    val newList = list.map { it.toUpperCase() }
    for (i in newList){
        println(i)
    }
}
  • filter:过滤集合中的数据,可以单独使用,也可以配合map函数一起使用。例如:
fun main() {
    val list = listOf("nayufeng", "wangruike", "ningmengcha")
    val newList = list.filter {it.length <= 9}.map { it.uppercase() }
    for (i in newList) {
        println(i)
    }
}
  • anyall:判断结婚中是否存在/全部元素满足条件。
2.2.3 Java函数式API

在Kotlin中调用Java方法时也可以使用函数式API,要求是:该Java方法跖接受一个Java单抽象方法接口参数(即接口中只有一个待实现方法)。

他妈的,没学过Java,书上的例子什么匿名泪实例的看不太懂。反正Kotlin更简单就对了。

2.3 空指针检查

Kotlin默认参数都必须是非空的。Kotlin将空指针异常的检查提前到了编译时期,如果程序存在空指针异常的风险,那么在编译时期就会直接报错,修正后才可以运行。

那如果想要需要某个参数或变量可空怎么办?只需要在类名后加一个问号就可以了。例如:

fun main() {
    doStudy(null)
}

fun doStudy(study: Study?){
    if (study != null){
        study.readbooks()
    	study.doHomework()
    }
}

注意:如果这里没有加if判断语句来判断study是否为空,那么编译是无法通过的。

2.3.1 判🈳️辅助工具
  • ?.操作符:当对象不为空时正常调用相应的方法,当对象为空时则什么都不做。例如
if (a != null) {
    a.doSomething()
}

这段代码用该操作符可以简单表示为:

a?.doSomething()
  • ?:操作符:左右两边各接受一个表达式。如果左边表达式结果不为空就返回左边表达式的结果;否则返回右边表达式的结果。例如
val c = if (a != null) {
	a
} else {
	b
}

这段代码用该操作符可以简单表示为:

val c = a ?: b
  • !!:非空断言工具:加在参数后面表示我确信这个参数不可能为空。
  • let:这是一个函数,提供了函数式API的编程接口,并将原始调用对象作为参数传递到了Lambda表达式中。那么它和空指针检查有什么关系呢?请看:上文的Study函数如果改用?.表达式,代码会是这样的:
fun doStudy(study: Study?){
    study?.readbooks()
   	study?.doHomework()
}

实际上,每个?.操作符都是一次if判断语句,因此这里本来只需要一个if,但受限于?.本身的性质,还是啰嗦地执行了两次判断。但是我们可以通过使用let函数来改写一下:

fun doStudy(study : Study?){
    study?.let {
        it.readbooks()
        it.doHomework()
    }
}

同时,let函数还可以解决全局变量的判空问题。全局变量随时可能被其他线程修改,所以即使用if做了判空处理也无法保证其函数体内的参数不为空。

2.4 Kotlin中的小魔术

2.4.1 字符串内嵌表达式

在字符串中用${ }嵌入表达式。当表达式中只有一个变量时,还可以将大括号省略。例如:

val brand = "Huawei"
val price = 9999
println("Cellphone(brand = $brand, price = $price)")
2.4.2 函数参数的默认值

直接看代码吧。

fun printParams(num: Int = 100, str: String){
	println("num is $num, str is $str")
}
printParams(srt = "world") // 这里必须要写str=,不然kotlin默认将“world”传给第一个参数
  • 23
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值