Android第二课-----Kotlin入门

本文介绍了Kotlin的发展历史,对比其与Java的优胜之处,涉及工作原理、运行、语法详解(变量、函数、逻辑控制、OOP、Lambda、空指针检查和小技巧),助你快速上手Kotlin开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Kotlin的发展历程

2011年,JetBrains发布了Kotlin的第一个版本,并在2012年将其开源。

2016年Kotlin发布了1.0正式版,代表着Kotlin语言已经足够成熟和稳定了,并且JetBrains也在自家的旗舰IDE开发工具IntelliJ IDEA中加入了Kotlin的支持。

2017年Google宣布Kotlin正式成为Android开发一级语言,并且Android Studio也加入了对Kotlin的支持。

2019年Google正式宣布了Kotlin First,未来提供的官方API也将会以Kotlin版本为主。


二、Kotlin相比于Java的优势

  • 语法更加简洁,对于同样的功能,使用Kotlin开发的代码量可能会比使用Java开发的减少50%甚至更多;
  • 法更加高级,相比于Java比较老旧的语法,Kotlin增加了很多现代高级语言的语法特性,使得开发效率大大提升;
  • 语言更加安全,Kotlin几乎杜绝了空指针这个全球崩溃率最高的异常;
  • 和Java是100%兼容的,Kotlin可以直接调用使用Java编写的代码,也可以无缝使用Java第三方的开源库。这使得Kotlin在加入了诸多新特性的同时,还继承了Java的全部财富;

三、Kotlin的工作原理

Kotlin可以做到和Java 100%兼容,这主要是得益于Java虚拟机的工作机制。

其实Java虚拟机并不会直接和你编写的Java代码打交道,而是和编译之后生成的class文件打交道。

而Kotlin也有一个自己的编译器,它可以将Kotlin代码也编译成同样规格的class文件。

Java虚拟机不会关心class文件是从Java编译来的,还是从Kotlin编译来的,只要是符合规格的class文件,它都能识别。

也正是这个原因,JetBrains才能以一个第三方公司的身份设计出一门用来开发Android应用程序的编程语言。


四、如何运行Kotlin代码

第一种方法是使用IntelliJ IDEA:
在这里插入图片描述
第二种方法是在线运行Kotlin代码。JetBrains专门提供了一个可以在线运行Kotlin代码的网站,地址是:https://try.kotlinlang.org

第三种方法是使用Android Studio。在任意Android工程中创建一个Kotlin文件,并编写一个main()函数,即可运行main()函数中的Kotlin代码:
在这里插入图片描述


五、Kotlin语法

1、变量

Kotlin中定义一个变量,只允许在变量前声明两种关键字:valvar

  • val(value的简写):用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量;
  • var(variable的简写):用来声明一个可变的变量,这种变量在初始赋值之后仍然可以再被重新赋值,对应Java中的非final变量;
fun main() {
	val a = 10
	var b = 5
	printIn("a="+a);
	printIn("b="+b);
}

Kotlin完全抛弃了Java中的基本数据类型,全部使用了对象数据类型。在Java中int是整型变量的关键字,而在Kotlin中Int变成了一个类,它拥有自己的方法和继承结构。
在这里插入图片描述

2、函数

fun methodName(param1: Int, param2: Int): Int {
	return 0
}
  • fun(function的简写):定义函数的关键字,无论定义什么函数,都一定要使用fun来声明;
  • methodName:函数名,良好的编程习惯是函数名最好要有一定的意义,能表达这个函数的作用是什么;
  • 函数名后面的一对括号中,可以声明该函数接收什么参数;
  • 括号后面的部分是可选的,用于声明该函数会返回什么类型的数据。如果不需要返回任何数据,这部分可以不写;
  • 两个大括号之间的内容就是函数体了,可以在这里编写函数的具体逻辑;

当一个函数的函数体中只有一行代码时,可以使用单行代码函数的语法糖:

fun methodName(param1: Int, param2: Int) = 0
  • 使用这种写法,可以直接将唯一的一行代码写在函数定义的尾部,中间用等号连接即可;
  • return关键字也可以省略,等号足以表达返回值的意思;
  • Kotlin还拥有出色的类型推导机制,可以自动推导出返回值的类型;

3、逻辑控制

3-1、if条件语句

Kotlin中的if语句相比于Java有一个额外的功能:它是可以有返回值的,返回值就是if语句每一个条件中最后一行代码的返回值:

fun largerNumber(num1: Int, num2: Int): Int {
	val value = if(num1 > num2) {
		num1
	}else {
		num2
	}
	
	return value
}

也可以写成如下:

fun largerNumber(num1: Int, num2: Int): Int {
	return if(num1 > num2) {
		num1
	}else {
		num2
	}
}

当一个函数只有一行代码时,可以省略函数体部分,直接将这一行代码使用等号串联在函数定义的尾部。虽然largerNumber()函数不止只有一行代码,但是它和只有一行代码的作用是相同的,只是return了一下if语句的返回值而已,符合该语法糖的使用条件,那么代码可以进一步精简:

fun largerNumber(num1: Int, num2: Int) = if(num1 > num2) {
	num1
}else {
	num2
}

最后,还可以将上述代码再精简一下,直接压缩成一行代码:

fun largerNumber(num1: Int, num2: Int) = if(num1 > num2) num1 else num2

3-2、when条件语句

当需要判断的条件非常多的时候,可以考虑使用when语句来替代if语句,when和Java中的switch差不多

fun getScore(name: String) = when(name) {
	"Tom" -> 86		//name=="Tom",返回77
	"Jim" -> 77		//
	"Jack" -> 95		//
	"Lily" -> 100		//
	else -> 0			//default返回0
}

除了精确匹配之外,when语句还允许进行类型匹配:

fun checkNumber(num: Number) {
	when(num) {
		is Int -> printIn(“number is Int”);					//num是Int类型
		is Double -> printIn("number is Double")		//num是Double类型
		else -> printIn("number not support")			//
	}
}

when的分支条件可以为任意表达式:

fun log(any: Any) {
	when(any) {
		"1" -> print("输入的内容为数字1")
		is String -> print("输入的内容是String类型的任意变量")
		setOf("0", "A") -> print("输入的内容是数字0和字母A的集合")
		Person.Dad.personName -> print("输入的内容是枚举类Person中变量Dad的姓名")
	}
}

when可以接收任意表达式为分支条件,而switch只能接收常量为分支条件,显然when语句在功能实现上会大大提高我们的效率和代码可读性;

when可以不带任何参数

fun log(any: Any) {
	when {
		any is Int -> print("输入的内容是Int类型的任意变量")
		any is String -> print(输入的内容是String类型的任意变量)
	}
}

注意:当when语句无参时,分支条件必须是任意的boolean表达式。

3-3、for-in循环语句

Kotlin可以用如下代码来表示一个区间(闭区间):

val range = 0..10		//[0,10]

也可以使用关键字until关键字来创建一个左闭右开的区间:

val range = 0 until 10		//[0,10)

如果想创建一个降序的区间,可以使用downTo关键字:

val range = 10 downTo 1

有了区间之后,就可以通过for-in循环来遍历这个区间了:

fun main() {
	for(i in 0..10) {
		println(i)
	}
}

遍历过程中如果想跳过其中的一些元素,可以使用step关键字,step定义步数,默认为1,就是正常遍历:

fun main() {
	for(i in 0 until 10 step 2) {
		println(i)
	}
}

在这里插入图片描述

4、面向对象编程

4-1、类与对象

可以使用如下代码定义一个类,以及声明它所拥有的字段和函数:

class Person {
	var name = ""
	var age = 0
	
	fun eat() {
		println(name + " is eating. He is " + age + " years old.")
	}
}

然后使用如下代码创建对象,并对对象进行操作:

fun main() {
	val p = Person();
	p.name = "Jack"
	p.age = 19
	p.eat()
}

4-2、继承

Kotlin中的一个类默认是不可以被继承的,如果想要让一个类可以被继承,需要主动声明oepn关键字:

open class Person {
	......
}

要让另一个类去继承Person类,则需要使用冒号关键字:

class Student : Person() {
	var sno = ""
	var grade = 0
}

现在Student类中就自动拥有了Person类中的字段和函数,还可以定义自己独有的字段和函数;

4-3、接口

Kotlin中定义接口的关键字和Java中是相同的,都是使用interface:

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

而Kotlin中实现接口的关键字变成了冒号,和继承使用的是同样的关键字:

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

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

4-4、数据类

Kotlin中使用data关键字可以定义一个数据类:

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

Kotlin会根据数据类的主构造函数中的参数将equals()、hashCode()、toString()等固定且无实际逻辑意义的方法自动生成,从而大大减少了开发的工作量;

4-5、单例类

Kotlin中使用object关键字可以定义一个单例类;

object Singleton {
	fun singletonTest() {
		println("singletonTest is called.")
	}
}

而调用单例类中的函数比较类似于Java中静态方法的调用方式:

Singleton.singletonTest()

这种写法虽然看上去像是静态方法的调用,但其实Kotlin在背后自动帮我们创建了一个Singleton类的实例,并且保证全局只会存在一个Singleton实例;

5、Lambda编程

5-1、集合的创建

初始化一个List集合

val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")

初始化一个Set集合

val set = setOf("Apple", "Banana", "Orange", "Pear", "Grape")

初始化一个Map集合

val map = mapOf("Apple" to 1, "Banana" to 2, "Orange" to 3, "Pear" to 4, "Grape" to 5)

5-2、Lambda表达式

Lambda就是一小段可以作为参数传递的代码,正常情况下,我们向某个函数传参时只能传入变量,而借助Lambda却允许传入一小段代码:

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

首先最外层是一对大括号,如果有参数传入到Lambda表达式中的话,我们还需要声明参数列表,参数列表的结尾使用一个->符号,表示参数列表的结束以及函数体的开始,函数体中可以编写任意行代码,并且最后一行代码会自动作为Lambda表达式的返回值

5-3、集合的函数式API

集合中的map函数是最常用的一种函数式API,它用于将集合中的每个元素都映射成一个另外的值,映射的规则在Lambda表达式中指定,最终生成一个新的集合。比如,这里我们希望让所有的水果名都变成大写模式,就可以这样写:

fun main() {
	val list = listOf("Apple", "Banana", "Orange", "Pear", "Grape")
	val newList = list.map({fruit: String -> fruit.toUpperCase()})
	for(fruit in newList) {
		println(fruit)
	}
}

在这里插入图片描述

  • 当Lambda参数是函数的最后一个参数时,可以将Lambda表达式移到函数括号的外面;
  • 如果Lambda参数是函数的唯一一个参数的话,还可以将函数的括号省略;
  • 由于Kotlin拥有出色的类型推导机制,Lambda表达式中的参数列表其实在大多数情况下也不必声明参数类型;
  • 当Lambda表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替

因此,Lambda表达式的写法可以进一步简化成如下方式:

val newList = list.map{it.toUpperCase()}

5-4、Java函数式API

如果我们在Kotlin代码中调用了一个Java方法,并且该方法接收一个Java单抽象方法接口参数,就可以使用函数式API。Java单抽象方法接口指的是接口中只有一个待实现方法,如果接口中有多个待实现方法,则无法使用函数式API。

举个例子,Android中有一个极为常用的点击事件接口OnClickListener,其定义如下:

public interface OnClickListener {
     void onClick(View v);
}

可以看到,这是一个单抽象方法接口。假设现在我们拥有一个按钮button的实例,就可以使用函数式API的写法来注册这个按钮的点击事件:

button.setOnClickListener { v ->
}

6、空指针检查

空指针是一种不受编程语言检查的运行时异常,只能由程序员主动通过逻辑判断来避免,但即使是最出色的程序员,也不可能将所有潜在的空指针异常全部考虑到

public void doStudy(Study study) {
    study.readBooks();
    study.doHomework();
}

这段Java代码安全吗?不一定,因为这要取决于调用方传入的参数是什么,如果我们向doStudy()方法传入了一个null参数,那么毫无疑问这里就会发生空指针异常。因此,更加稳妥的做法是在调用参数的方法之前先进行一个判空处理,如下所示:

public void doStudy(Study study) {
    if (study != null) {
        study.readBooks();
        study.doHomework();
    }
}

6-1、可空类型系统

Kotlin中引入了一个可空类型系统的概念,它利用编译时判空检查的机制几乎杜绝了空指针异常

fun doStudy(study: Study) {
	study.readBooks()
	study.doHomework()
}

这段代码看上去和刚才的Java版本并没有什么区别,但实际上它是没有空指针风险的,因为Kotlin默认所有的参数和变量都不可为空,所以这里传入的Study参数也一定不会为空,可以放心地调用它的任何函数。

Kotlin提供了另外一套可为空的类型系统,就是在类名的后面加上一个问号。比如,Int表示不可为空的整型,而Int?就表示可为空的整型;String表示不可为空的字符串,而String?就表示可为空的字符串。

使用可为空的类型系统时,需要在编译时期就把所有的空指针异常都处理掉才行。

6-2、判空辅助工具

Kotlin提供了一系列的辅助工具,使开发者能够更轻松地进行判空处理。
?. 操作符表示当对象不为空时正常调用相应的方法,当对象为空时则什么都不做。比如:

if (a != null) {
    a.doSomething()
}

这段代码使用?.操作符就可以简化成:

a?.doSomething()

?: 操作符表示如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果。比如:

val c = if (a ! = null) {
a
} else {
b
}

这段代码的逻辑使用?:操作符就可以简化成:

val c = a ?: b


结合使用?.操作符和let函数也可以对多次重复调用的某个变量统一进行判空处理:

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

7、Kotlin中的小魔术

7-1、字符串内嵌表达式

在Kotlin中,我们可以直接将表达式写在字符串里面,即使是构建非常复杂的字符串,也会变得轻而易举。

Kotlin中字符串内嵌表达式的语法规则如下:

"hello, ${obj.name}. nice to meet you!"

当表达式中仅有一个变量的时候,还可以将两边的大括号省略:

"hello, $name. nice to meet you!"

7-2、函数参数默认值

Kotlin允许在定义函数的时候给任意参数设定一个默认值,这样当调用此函数时就不会强制要求调用方为此参数传值,在没有传值的情况下会自动使用参数的默认值。语法格式如下:

fun printParams(num: Int, str: String = "hello") {
    println("num is $num , str is $str")
}

这里给printParams()函数的第二个参数设定了一个默认值,这样当调用printParams()函数时,可以选择给第二个参数传值,也可以选择不传,在不传的情况下就会自动使用默认值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值