全网最全面的由浅到深的Kotlin基础教程
前言
kotlin是google全力推行的语言,如果你是从事android相关的研发,掌握kotlin语言是非常有必要的,因为现在google的很多新技术以及接口都是用kotlin语言实现的,如果你不懂kotlin语言,那么你就很难跟上google的最新技术。
其次,kotlin语言真的是集所有语言之大成,kotlin可以兼容目前主流的编程语言,而且kotlin代码精简之程度,真的是目前任何语言都无法比拟的,这一点,我也是认真学习完之后才体会到的,相信你看完本文,就能体会到kotlin语言的简洁程度。
总之,因为kotlin语言是集所有语言之大成,学习完kotlin也一定程度上可以让你加深对其它语言,尤其是java语言的进一步理解。我将通过7篇博文,完成kotlin入门系列教程,本篇是系列的开篇,下一篇是全网最全面的由浅到深的Kotlin基础教程(二)
那么,下面就开始我们的kotlin学习之旅吧,坚持看完本系列文章,你将掌握一门非常灵活的编程语言,相信一定会收获满满。
特别鸣谢Derry老师~~
如果想要看视频学习的,可以去B站看Derry老师的视频,Android Kotlin从入门到进阶全套教程
1. 声明变量及内置数据类型
- 声明变量格式:
可读可写var/只读val 变量名 变量类型 值 - 声明变量示例
//声明可读可写的String类型变量name
var name:String ="sun"
//声明只读的String类型变量info
val info:String = "my info"
- kotlin内置变量类型
String
Char
Boolean
Int
Float
Double
List 集合
Set 无重复集合
Map 键值对
- kotlin输入函数println
var name:String ="sun"
name="hao"
println(name);
2. 类型推断
kotlin具有类型推断的能力,如果类型没有歧义,可以省略指定类型,由编译器自动推断类型。
//val age:Int = 18
val age = 18 //如编译器可以推断出age的类型为Int,因此类型Int可以省略
3. 定义编译时常量
通过const修饰val变量,定义编译时常量
const val PI =3.1415926
4. 查看反编译后的字节码/java代码
kotlin可以兼容Java代码,IDEA工具通过Tools -->Kotlin --> Show Kotlin Bytecode --> Decompile可以查看kotlin反编译为java的代码。通过反编译工具,可以深入理解kotlin的实现逻辑。
如下kotlin代码
package com.kt.base
// TODO 编译时常量
const val PI =3.1415926
fun main() {
println(PI)
}
通过IDEA查看反编译为java代码如下,从反编译的java代码可见,kotlin所谓的const val变量转为java代码,其实就是static final变量。
package com.kt.base;
import kotlin.Metadata;
@Metadata(
mv = {
1, 7, 0},
k = 2,
d1 = {
"\u0000\u000e\n\u0000\n\u0002\u0010\u0006\n\u0000\n\u0002\u0010\u0002\n\u0000\u001a\u0006\u0010\u0002\u001a\u00020\u0003\"\u000e\u0010\u0000\u001a\u00020\u0001X\u0086T¢\u0006\u0002\n\u0000¨\u0006\u0004"},
d2 = {
"PI", "", "main", "", "KotlinLearn"}
)
public final class Kt04Kt {
public static final double PI = 3.1415926;
public static final void main() {
double var0 = 3.1415926;
System.out.println(var0);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
5. range表达式
用于范围判断
fun main() {
val score = 99
if (score in 60..100) {
println("及格")
} else {
println("不及格")
}
}
6. when表达式
类似java的switch case
fun main() {
var week = 6
var info = when(week){
1 -> "星期一"
2 -> "星期二"
3 -> "星期三"
4 -> "星期四"
5 -> "星期五"
else -> {
println("星期不知道") //Unit就是java中的void返回类型
}
}
println(info)
}
7. String模板
kotlin String可以通过$符号进行变量引用和逻辑编写等。
fun main() {
var address = "北京"
var feel = "很好"
println("今天我去${
address}玩了,我感觉${
feel}")
//kotlin的if是表达式,更灵活,java的if是语句
var isLogin = true
println("当前登录状态 ${
if (isLogin) "登录成功" else "登录失败"}")
}
8. 函数学习
8.1 函数头学习
函数格式
修饰符 fun 方法名(参数名:类型):返回类型{}
//不写修饰符,默认为public
private fun method1(age:Int, name:String):Int{
println("你的名字是$name,你的年龄是$age")
return 200
}
8.2 函数参数的默认参数
fun main() {
method1() //省略参数,则采用默认的参数
}
private fun method1(name:String="sun", age:Int=18){
println("你的名字是$name,你的年龄是$age")
}
8.3 具名函数参数
不依靠函数参数的顺序确定参数值,而是直接指定参数名确定参数值。
fun main() {
method1(age=18, name="sun")
}
private fun method1(name:String, age:Int){
println("你的名字是$name,你的年龄是$age")
}
8.4 Unit函数的特点
Unit函数即java中返回值void的函数
// Unit返回类型可以省略不写
private fun method1():Unit
{
}
8.5 Nothing类型的特点
kotlin中Nothing类型的函数就是java中抛异常的函数,用于抛出异常。
官方对于Nothing类的定义及介绍如下,简言之,就是通过抛异常,处理不存在值的情况。
/** * Nothing has no instances. You can use Nothing to represent "a value that never exists": for example, * if a function has the return type of Nothing, it means that it never returns (always throws an exception). */
public class Nothing private constructor()
如kotlin中TODO函数的返回类型就是Nothing,用于抛出异常。
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
TODO函数使用示例
private fun method1(score:Int){
when(score){
-1 -> TODO("没有这种情况")
in 0..60 -> "不及格"
in 61..70 -> "及格"
in 71..100 -> "优秀"
}
}
8.6 反引号(`)中函数名特点:
kotlin可以通过反引号,定义一些违反命名规则的方法
fun main() {
`我的函数`("sun", 18)
}
private fun `我的函数`(name:String, age:Int){
println("name:${
name},age:$age")
}
8.7 定义函数类型 & 隐式返回
- 定义函数类型:可以像定义基础变量一样定义函数类型
- 隐式返回:把函数体中的最后一行作为返回值
代码示例如下:
fun main() {
//1. 函数声明 方法名:输入->输出
val method1:()->String
//2. 函数实现
method1 = {
//匿名函数不用写return,最后一行就是返回值
"success"
}
//3. 函数调用
println(method1())
}
8.8 匿名函数的学习
上面8.7节定义的函数类型,推荐通过下面的方式直接进行匿名实现,而不必,先定义函数,再去实现函数。下面的示例就是匿名函数写法。
fun main() {
//1. 函数声明 方法名:输入->输出,及函数实现【这种匿名写法与下面的函数效果一致】
val method1:(String,Int)->String = {
name, age ->
"name:$name,age:$age"
}
//3. 函数调用
println(method1("sun", 18))
}
private fun method1(name:String,age:Int):String{
return "name:$name,age:$age"
}
8.9 it关键字特点
匿名函数如果只有一个参数,默认参数名为it,当然你也可以指明参数名。
fun main() {
val method1:(Int)->String = {
"it=$it"
}
println(method1(66))
}
8.10 匿名函数的类型推断
匿名函数有两种写法:
- 可以进行类型推断的写法:
方法名 = {入参类型 -> code body} - 不可以进行类型推断的写法:
方法名 : (入参类型) -> 返回类型 = {入参名 -> code body}
关于类型推断很简单,只要没有歧义,确定是某一种类型,编译器都可以进行类型推断。
fun main() {
//匿名函数写法一(可以进行类型推断,不需要写返回类型) 方法名 = {入参 -> code body}
val method = {
v1:Int, v2:String ->
"v1:$v1,v2:$v2"
}
println(method(18, "sun"))
//匿名函数写法二(无法进行类型推断):方法名 : (入参类型) -> 返回类型 = {入参名 -> code body}
val method1 : (Int, String) -> String = {
v1, v2 ->
"v1:$v1,v2:$v2"
}
println(method1(18, "hao"))
}
8.11 lambda表达式学习
匿名函数属于lambda表达式,即上面学习的匿名函数就是lambda表达式。
fun main() {
//add 匿名函数也就是lambda表达式
val add = {
num1:Int, num2:Int ->
"add = ${
num1+num2}"
}
println(add(1,5))
//week 匿名函数也就是lambda表达式
val week = {
num:Int ->
when(num){
1 -> "星期1"
2 -> "星期2"
3 -> "星期3"
4 -> "星期4"
5 -> "星期5"
else -> -1
}
}// week : (Int) -> Any
println(week(1))
}
8.12 函数中定义参数为函数
即函数参数为lambda表达式,如果用java,就需要用接口实现。
fun main() {
loginAPI("mekeater", "123") {
msg:String, code:Int ->
println("登录结果 msg:$msg,code:$code")
}
}
//将函数通过lambda表达入参,如果用java,就需要用接口实现
fun loginAPI(name:String, pwd:String, responseResult: (String, Int) -> Unit)
{
if (name == "mekeater" && pwd == "123")
{
responseResult("登录成功", 200)
}
else{
responseResult("登录失败", 444)
}
}
8.13 函数内联学习
- 通过inline修饰符可以将函数指定为内联函数。
- 建议函数参数中有lambda表达式的函数,都声明为内联函数,否则,调用端会生成多个对象才能完成lambda的调用,影响程序性能。你可以通过反编译为java代码查看这一事实。
fun main() {
loginAPI1("mekeater", "123") {
msg:String, code:Int ->
println("登录结果 msg:$msg,code:$code")
}
}
//将函数通过lambda表达入参,如果用java,就需要用接口实现
inline fun loginAPI1(name:String, pwd:String, responseResult: (String, Int) -> Unit)
{
if (name == "mekeater" && pwd == "123")
{
responseResult("登录成功", 200)
}
else{
responseResult("登录失败", 444)
}
}
8.14 函数引用学习
lambda表达式参数如果采用具体函数实现,则需要通过函数引用(::)进行调用。示例代码如下:
fun main() {
//lambda属于函数类型的对象,需要把responseMethod方法转变为 函数类型的对象(函数引用::)
val obj = ::responseMethod
login("mekeater", "123", obj)
}
//lambda表达式具名函数实现
private fun responseMethod(msg:String, code:Int){
println("登录情况 msg:$msg, code:$code")
}
inline fun login(name:String,psw:String, responseResult:(String, Int)->Unit){
if (name == "mekeater" && psw == "123")
{
responseResult("登录成功", 200)
}
else{
responseResult("登录失败", 444)
}
}
8.15 函数类型作为返回类型
即以lambda表达式作为函数的返回类型。
fun main() {
var show = show("返回匿名函数")
println(show("sun", 18))
}
fun show(info: String): (String, Int) -> String {
println("info$info")
return {
name: String, age: Int ->
"name:$name, age:$age"
}
}
8.16 匿名函数与具名函数
上面也提到了,lambda表达式匿名实现的称为匿名函数,lambda表达式单独用一个函数实现的,称为具名函数。示例如下:
fun main() {
//lambda表达匿名实现,匿名函数
show("sun", "he is a success man") {
println("result = $it")
}
//showResultImpl是具名函数
show("sun", "he is a success man", ::showResultImpl)
}
//具名函数
fun showResultImpl(result:String){
println("result = $result")
}
inline fun show(name:String, info:String, showResult:(String)->Unit){
val str = "name:$name,info:$info"
showResult(str)
}
文章评论