《第一行代码》笔记(一)-Kotlin语法
变量
在Kotlin中,变量分有val
(value)和var
(variable)修饰的变量类型,由于Kotlin有类型推导机制,因此可以不声明变量数据类型。
1 | val a = 10 |
当然我们也可以显性地声明变量类型:
1 | val a: Int = 10 |
和Java不同的是,在Kotlin中每个变量类型都是类,因此变量类型都是开头大写的
函数
函数体如下所示:
1 | fun methodName(param1: Int, param2: Int): Int { |
首先fun(function的简写)是定义函数的关键字,无论你 定义什么函数,都一定要使用fun来声明。
紧跟在fun后面的是函数名,这个就没有什么要求了,你可以根据自己的喜好起任何名字,但是 良好的编程习惯是函数名最好要有一定的意义,能表达这个函数的作用是什么。
函数名后面紧跟着一对括号,里面可以声明该函数接收什么参数,参数的数量可以是任意多 个,例如上述示例就表示该函数接收两个Int类型的参数。参数的声明格式是“参数名: 参数类 型”,其中参数名也是可以随便定义的,这一点和函数名类似。如果不想接收任何参数,那么写 一对空括号就可以了。
参数括号后面的那部分是可选的,用于声明该函数会返回什么类型的数据,上述示例就表示该 函数会返回一个Int类型的数据。如果你的函数不需要返回任何数据,这部分可以直接不写。
最后两个大括号之间的内容就是函数体了,我们可以在这里编写一个函数的具体逻辑。由于上 述示例中声明了该函数会返回一个Int类型的数据,因此在函数体中我们简单地返回了一个0。 这就是定义一个函数最标准的方式了
函数语法糖
如果函数只有一行代码时,我们可以不必写函数体:
1 | fun largerNumber(num1: Int, num2: Int): Int = max(num1, num2) |
我们也可以借助Kotlin的类型推导机制再简化
1 | fun largerNumber(num1: Int, num2: Int) = max(num1, num2) |
逻辑控制
if条件语句
标准型
1 | fun largerNumber(num1: Int, num2: Int): Int { |
语法糖
我们可以直接用if
语句给value
赋值
1 | fun largerNumber(num1: Int, num2: Int): Int { |
当然我们也可以直接return
出去
1 | fun largerNumber(num1: Int, num2: Int): Int { |
我们发现只有一个return
语句,因此可以继续化简:
1 | fun largerNumber(num1: Int, num2: Int): Int = if(num1 > num2) { |
when条件语句
标准式
匹配值 -> { 执行逻辑 }
当你的执行逻辑只有一行代码时,{ }可以省略。
1 | fun getScore(name: String) = when(name) { |
类型匹配
1 | fun checkNumber(num: Number) { |
特殊场景
1 | fun getScore(name: String) = when { |
循环语句
while
循环没区别不说了
区间
1 | val range = 0..10 |
面对对象编程
类与对象
和java没什么区别
1 | class Person { |
继承与构造函数
继承
1 | class Student { |
我们需要注意的是,Kotlin中默认类是不允许继承的!
我们需要加上open
关键字:
1 | open class Person { ... } |
这样子Person
类才可以被继承
第二件事,要让Student类继承Person类。在Java中继承的关键字是extends,而在Kotlin 中变成了一个冒号,写法如下:
1 | class Student : Person() { |
可见性修饰
构造函数
1 | class Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age) { |
Student(val sno: String, val grade: Int, name: String, age: Int) : Person(name, age)
是主构造函数,init为可选的主构造函数,可以在里面添加逻辑其中的
constructor
均为次构造函数
任何一个类只能有一个主构造函数,但是可以有多个次构造函数。次构造函数也可 以用于实例化一个类,这一点和主构造函数没有什么不同,只不过它是有函数体的。
当然我们可以直接用参数默认值简化:
1 | class Student(val sno: String = "", val grade: Int = 0, name: String = "", age: Int = 0) : Person(name, age) { } |
这样子就不需要次构造函数了
接口
接口可以不需要函数体,若没有函数体,继承的类需要覆盖;若有,继承的类可以不覆盖
接口的继承不需要括号
1 | interface Study { |
1 | class Student(name: String, age: Int) : Person(name, age), Study { |
数据类与单例类
数据类
数据类通常需要重写equals()、hashCode()、toString()这几个方法。其中,equals() 方法用于判断两个数据类是否相等。hashCode()方法作为equals()的配套方法,也需要一起 重写,否则会导致HashMap、HashSet等hash相关的系统类无法正常工作。toString()方法 用于提供更清晰的输入日志,否则一个数据类默认打印出来的就是一行内存地址。
New→Kotlin File/Class,在弹出的对话框中输 入“Cellphone”,创建类型选择“Class”。然后在创建的类中编写如下代码:
1 | data class Cellphone(val brand: String, val price: Double) |
当在一个类前 面声明了data关键字时,就表明你希望这个类是一个数据类,Kotlin会根据主构造函数中的参 数帮你将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成, 从而大大减少了开发的工作量。
单例类
java中的单例模式:
1 | public class Singleton { |
而如果我们想调用单例类中的方法,也很简单,比如想调用上述的singletonTest()方法, 就可以这样写:
1 | Singleton singleton = Singleton.getInstance(); |
在Kotlin中创建一个单例类的方式极其简单,只需要将class关键字改成object关键字即可。 现在我们尝试创建一个Kotlin版的Singleton单例类,右击com.example.xxx包 →New→Kotlin File/Class,在弹出的对话框中输入“Singleton”,创建类型选择“Object”,点 击“OK”完成创建,初始代码如下所示:
1 | object Singleton { } |
现在Singleton就已经是一个单例类了,我们可以直接在这个类中编写需要的函数,比如加入 一个singletonTest()函数:
1 | object Singleton { |
如果我们想调用直接:
1 | Singleton.singletonTest() |
这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个 Singleton类的实例,并且保证全局只会存在一个Singleton实例。
Lambda编程
集合API
列表
1 | val list = ArrayList<String>() |
我们可以直接用
1 | val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape") |
Map集合
1 | val map = HashMap<String, Int>() |
集合的函数式API
maxby
1 | val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon") |
我们可以用下面的来改写:
1 | val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon") |
我们来看一下Lambda表达式的语法结构:
{参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}
因此上面代码的lambda表示其实是:
1 | val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape", "Watermelon") |
然后Kotlin规定,当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括 号的外面,且如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略,同时Lambda表达式中的参数列表其实在大多数情况下不必声明参数类型,最后,当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it 关键字来代替。因此:
1 | //当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括 号的外面 |
map
1 | fun main() { |
filter
1 | fun main() { |
any和all
1 | fun main() { |