语句块

kotlin是以{ }来表示一段语句块

变量

与java不同的是

Kotlin在定义一个变量,只允许在变量前申明两种关键词: val 和 var

  • val(value的简写)用来声明一个不可变的变量,对应java中的final变量
  • var(variable的简写)用来声明一个可变的变量

一般会自动推理变量类型(Int,Float)

kotlin内的变量类型名首字母大写,其他与java语言一致

但也可直接声明类型:

1
val a:Int =10

对于变量优先使用val类型,在不能满足需求时换var类型

函数

1
2
3
fun methodName(param1:Int,param2:Int){
return 0
}
  • 同时对于内置函数需要导包使用

    Android Studio内部有代码自动补全功能可以完成自动导包

一些简单的测试:

1
2
3
4
5
6
7
8
9
10
fun main(){
val x=37
val y=30
val value1=add(x,y)
println(value1)
}

fun add(param1:Int,param2: Int):Int {
return param1+param2
}

可以用语法糖实现只有一行代码的函数编写

1
fun add(param1:Int,param2:Int):Int = param1+param2

程序的逻辑控制

if语句

基本语法与java一致

if (条件){语句块}

1
2
3
4
5
6
7
8
fun Maxnum(num1:Int,num2:Int):Int {
var value=0
if(num1>num2){
value=num1
}else{
value=num2
}
}

when语句

有点像java里的switch语句,但有很大区别

  • 首先没有case加break的组合

基本语法为:

匹配值 -> { 执行逻辑 }

例子:

1
2
3
4
5
fun getnumber(name:String) = when(name){
"John" -> 86
"Jim" -> 77
"Jack" -> 100
}

但也可以将匹配值与对象直接用==来判断

1
2
3
4
5
fun getSore(name: String) = when{
name=="Jim" -> 77
name=="Jack" ->87
name.startsWith("Tom") -> 99
}

面向对象编程

类与对象

1
2
3
4
5
6
7
8
class Person{
var name=" "
var age=0

fun eat() {
println(name+"is eating. He is "+age+"years old.")
}
}
  • 调用对象
1
val p=Person()
  • 在main函数中使用Person对象
1
2
3
4
5
6
fun main(){
val p=Person()
p.name="Jack"
p.age=19
p.eat()
}

继承与构造函数

  1. 在kotlin中任何一个非抽象类默认都是不可继承的

    所以我们需要使用open关键词告诉编译器哪些类是可以继承的

如:

1
2
3
4
5
6
7
8
open class Person{
var name=" "
var age=0

fun eat() {
println(name+"is eating. He is "+age+"years old.")
}
}
  1. 使用一个类来继承可以继承的类的关键词: 一个冒号

    假设我们用Student类来继承Person类

如:

1
2
3
4
class Student : Person(){
var sno=""
var grade=0
}

主构造函数与次构造函数

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

次构造函数可以看成同名的另一个类构造

知识点:

  1. 继承类时,如果类是带参数的主构造函数,需要同时传入参数

如:

1
2
3
4
5
6
7
8
9
open class Person(var name:Sting,var age:Int){
fun eat(){
println(name=" is eating. He is "+age+" years old.")
}
}

class Student(name:Sting,age:Int) : Person(name,age){
...
}
  1. 次构造函数使用时也是

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

如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
open class Person(var name:Sting,var age:Int){
fun eat(){
println(name=" is eating. He is "+age+" years old.")
}
}

class Student(name:Sting,age:Int) : Person(name,age){
constructor(name:String,age:Int) : this("",0,name,age){

}
constructor():this("",0){
//调用上面的次构造函数的同时,将name和age赋值
}
}
  1. 类中只有次构造函数

如:

1
2
3
4
5
class Student : Person{
constructor(name:String,age:Int):super(name,age){

}
}

接口(interface)

例子:

1
2
3
4
interface Study{
fun readbooks()
fun doHomework()
}
  • 接口的使用同时也是使用冒号,当出现多个接口使用时用逗号隔开

    使用override对接口中的函数进行覆写

    1
    2
    3
    4
    5
    6
    7
    8
    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.")
    }
    }
  • 接口中的函数可以初始化

如:

1
2
3
4
5
6
7
8
interface Study{
fun readbooks(){
println("The method is init")
}
fun doHomework(){
println("finished")
}
}

函数可视化修饰符

修饰符 Java Kotlin
public 所有类可见 所有类可见
private 当前类可见 当前类可见
protected 当前类,子类,同一包路径下的类可见 当前类,子类可见
default 同一包路径下的类可见(默认)
internal 同一模块中的类可见

数据类与单例类

数据类

这一段因为从未使用过数据类只能照抄书中内容

  • 在一个规范的系统架构中,数据类通常占据着非常重要的角色,它们用于将服务器或数据库中的数据映射到内存中,为编程逻辑提供数据模型的支持。或许你听说过MVC,MVP,MVVM之类的架构模式,不管是哪一种架构模式,其中的M指的就是数据类

如java中构建手机数据类,只有品牌和价格两个字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Cellphone {
String brand;
double price;

public Cellphone(String brand, double price) {
this.brand = brand;
this.price = price;
}

@Override
public boolean equals(Object obj) {
if (obj instanceof Cellphone) {
Cellphone other = (Cellphone) obj;
return other.brand.equals(brand) && other.price == price;
}
return false;
}

@Override
public int hashCode() {
return brand.hashCode() + (int) price;
}

@Override
public String toString() {
return "Cellphone(brand=" + brand + ", price=" + price + ")";
}
}
  • 而kotlin中只需要一行代码即可实现:

如:

1
data class Cellphone(val brand: String,val price: Double)

测试方法:

1
2
3
4
5
6
7
fun main(){
val cellphone1=Cellphone("bird",1299.99)
val cellphone2=Cellphone("bird",1299.99)
println(cellphone1)
println(cellphone2)
println(cellphone1==cellphone2)
}

单例类

为避免创建重复的对象,这时可以使用单例类

创建方式: 把想要变成单例类的类的class改为object

1
2
3
4
5
object Singleton{
fun singletonTest(){
println("singletonTest is called.")
}
}

调用方式:

1
Singleton.singletonTest()

因为kotlin在背后自动帮我们创建了一个Singleton类的实例

Lambda 编程

这里只是一些基础使用

集合的创建与遍历

可以参考python中的元组,集合,字典

这里的集合包括:

  1. List
  2. Set
  3. Map

List

1
2
3
4
val list=listOf("Apple","Banana","Pear","Grape")
for(i in list){
println(i)
}

这里的集合类似于python中的元组,不可修改

Set

1
2
3
4
val set=setOf("Apple","Banana","Pear","Grape")
for(i in list){
println(i)
}

这里的集合类似于python中的集合,因为底层是使用hash映射来存放数据,无法保证有序性

map

1
2
3
4
val map=mapOf("Apple" to 1,"Banana" to 2,"Pear" to 3,"Grape" to 4)
for((fruit,number)in map){
println("fruit is "+fruit+", number is "+number)
}

这里的to不是关键字,而是infix函数

Lambda表达式

基本语法:

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

在 Kotlin 中有一个约定:如果函数的最后一个参数是函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外:

1
val product = items.fold(1) { acc, e -> acc * e }

当lambda是唯一参数时,可以省略括号

1
val maxLengthFruit = list.maxBy{fruit:String -> fruit.length}

当lambda中只有一个参数时,也不必声明参数名,用it代替

1
val maxLengthFruit = list.maxBy{it.length}

集合的函数式API

  1. map

    将集合中的每一个元素映射成一个另外的值

    1
    2
    3
    4
    5
    val list=listOf("Apple","Banana","Orange","Pear","Grape","Watermelon")
    val newlist=list.map{it.toUpperCase()}
    for(i in newlist){
    println(i)
    }
  2. filter

    用来过滤集合中的函数

    1
    2
    val list=listOf("Apple","Banana","Orange","Pear","Grape","Watermelon")
    val newlist=list.filter{it.leangth <= 5}
  3. any

    用来判断集合中是否存在一个元素符合条件

  4. all

    用来判断集合中是否所有元素符合条件

Java函数式API的使用

kotlin在调用Java方法时使用Java函数式API,只能调用只接受一个Java单抽象方法接口参数的Java函数式API。

如Java原生API中最为常见的单抽象方法接口—-Runnable接口

1
2
3
pubic interface Runnable{
void run();
}

kotlin用构造方法接收接口

1
Thread(Runnable{println("Thread is running")}).start()

在一个java方法中如果不存在一个以上的Java单抽象方法接口参数,可以对接口名省略

1
Thread{println("Thread is running")}.start()

在kotlin编写Android时会经常用到 Java API,如点击事件接口OnClickListener:

1
2
3
public interface OnClickListener{
void onClick(view v);
}

kotlin调用

1
button.setOnClickListener{ }

空指针检测

kotlin中是默认检测空指针异常的,所有如果有需要空数据时,需要以下方式调整操作系统

  • 可空类型系统

    就是在类名后面加上一个问号

    如: Int? 表示可空的整型,String?表示可空的字符串,String表示不可空的字符串

  • 判空辅助工具

  1. .? 操作符

    表示对象为空时不执行

  2. :? 操作符

    表示对象为空时,执行冒号右边的表达式

  3. !! 操作符

    非空断言工具

字符串内嵌表达式

${ }可以将变量嵌在字符串中,当内嵌表达式中只有一个变量时,{}号可以省略

如:

1
2
val name="Jack"
println("$name is running.")//println("${name} is running.")

函数的参数默认值

与python类似的做法:直接给参数赋值

1
2
3
4
5
6
7
fun main(){
printParams()
}

fun printParams(num:Int=100,str:String="hello"){
println("$str,the No.$num")
}