kotlin入门最容易教程一(最全,最详细)
0.环境准备
用到是IDEA免费版本。新建一个Kotlin项目。
取个名字。
最后新建一个.kt文件,就可以开始使用kotlin了。
选择创建File。之后就会生成一个.kt的文件。
HelloWorld程序:
fun main() {var str:String="Hello"println(str)
}
手动编译运行:
执行下面的代码会生成一个叫HelloKt.class的字节码文件,非常奇怪的是,命令行并没有提供什么参数来修改这个生成的文件名字。
kotlinc Hello.kt
通过kotlin命令行来执行字节码文件:
kotlin HelloKt.class
也可以通过下面的代码生成jar文件,然后通过java -jar来运行
kotlinc Hello.kt -d hello.jar
java -jar hello.jar
1.数据类型
1.1数据的声明
下面的代码声明了一个String类型的变量,通过var关键字来声明变量,和java相比,这个写法好像非常的麻烦,多了var关键字还多了冒号,而且写的顺序也不一样,类型声明在后面,据说这个语法是从TypeScript那里学过来的,对TypeScript(JS)不熟。既然设计成这样,一定是有他的好处的。实际上,类型可以省略,kotlin会自动帮我们推导出来。
fun main() {var str:String="Hello"println(str)
}
省略后的写法:
也就是不管什么类型,都可以声明为var类型。对于开发者来说,还是节省了一点时间的,虽然牺牲了一点效率,因为倒推类型肯定需要额外的内部操作。
fun main() {var str="Hello"println(str)
}
1.2只读变量
下面的代码声明了一个String类型的变量,但是编译器会给一个警告,说"Hello"是一个只读变量,可以用val声明。注意是最后一个字母是L而不是R,var和val是两个关键字。var可以用来声明一般的变量,val用来声明只读变量,类似于java的final关键字。
var str="Hello"
用val声明:
val str="Hello"
注意这个只读并不等于常量,常量是用另一个关键字const来修饰的。
1.3 const常量
常量只能声明在方法外部,在方法内部是不能声明常量的。
const val MAX=1024fun main() {println(MAX)
}
在kotlin中,const相对于java的static final。我们可以通过双击shitf,输入kotlin bytecode查看字节码信息。
public final static I MAX = 1024
1.4 引用类型
我们知道Java有引用类型和基本数据类型这两种类型。引用类型放在堆里面,一般是java对象。而kotlin只有一种类型,也就是引用类型,但是在编译的时候,还是会转化为基本类型。
val age=10
在字节码里面的LOCALVARIABLE I代表int类型。也就是会转化为基本数据类型。字节码内容了解一下就行。
LOCALVARIABLE age I L1 L6 0
2. 表达式
2.1 if else表达式
和Java的用法一样,就不写了。
2.2 range表达式
字面意思就是范围表达式,用到的关键字是in。下面这个例子很好的说明了使用的in关键字的用法。不光可以指定数字,还可以指定数组或者集合。
val score=66if (score in 0..60){println("bad")}else if (score in 61..80){println("not bad")}else{println("good")}
2.3 when表达式
相对于Java的switch表达式,但更加简洁,推荐将所有的if else表达式都转化成when的形式,when表达式在kotlin中是非常常用的。
下面的代码对比Java的switch语句少了case和default关键字看起来简洁了非常多。
而且可以返回多种数据类型,这里返回了String类型的“男”,“女”,和int类型的-1。
返回类似是Any类型,这个有点类似Java的Object类型。->实际上是一个lambda表达式。如果只有单行可以直接返回结果,不用写return;
val gender=3;val result:Any=when(gender){1->"男"2->"女"else-> -1}println(result)
如果lambda表达式存在多行,那么需要加一个大括号{}。
val gender=3;val result=when(gender){1->"男"2->"女"else-> {println("未知")println("程序退出")}}println(result)
程序最后输出如下,kotlin.Unit类似于Java的void,因为println并没有返回值。
未知
程序退出
kotlin.Unit
2.4 String模板
String模板就是String的拼接。在Java中,我们用++拼接字符串,这个实际上是非常麻烦的。很多语言都支持用符号拼接内容,用符号拼接内容,用符号拼接内容,用{}拼接表达式。
用$拼接内容:
val animal="dog"val color="yellow"println("The $animal's color is $color")
输出内容:
The dog's color is yellow
用${}拼接表达式:
val animal="dog"val color="yellow"val age=10println("The $animal's is $color and ${if(age>5) "old" else "young"}")
输出内容:
The dog's is yellow and old
3.函数
3.1 函数头
kotlin的函数头和Java还是差别非常大的,priavate表示权限,默认是oublic,fun是函数声明关键字,括号里面是参数列表,最后的:Boolean表示返回类型。
可以看到参数列表和返回值的顺序和Java是相反的,这实际上是更加符合逻辑的,先传输入再确定输出类型,也就是输入输出。只是Java用习惯了,也就习以为常了。
private fun doSomething(i:Int ,s:String):String{return "resultCode";
}
函数调用
直接调用就可以,不需要创建对象。
fun main() {val flag = doSomething(5, "abc")println(flag)
}
3.2 参数的默认值
参数还可以给默认值,只是Java所没有的,Java有固定的默认值。kotlin支持指定默认值。
private fun doSomething2(a:Int=2,s:String="null"):String{return "$a $s";
}fun main() {//没有传任何参数val result = doSomething2()println(result)
}
输出结果:
2 null
3.3 具名函数参数
具名的意思就是在传入参数的时候可以指定参数的名字,这样的目的是增加可读性,因为光传参数,不知道这个参数是干嘛用的,可能传错位置,可读性也很差。
例如下面的代码,代码一的位置,写了参数的名字是age,和name,这样就不会搞错参数位置了,可读性非常强。但是,IDEA是支持参数类型提示的,可以直接显示参数类型,这相对于是IDEA已经实现的功能,可能就是为了弥补Java没有这个功能而设计的。
fun main() {//代码一var flag=doSomething(age=5,name="abc")
}private fun doSomething(age:Int,name:String):Boolean{return true;
}
3.4 Unit函数
在Java中没有返回类型就返回void类型,但在泛型的时候,这个概念就有点矛盾。kotlin用kotlin.Unit这个类型表示没有返回类型。在kotlin中,如果没有返回类型,那么函数的返回类型可以不用写任何类型,也不用写void,kotlin根本就没有void这个关键字。
fun main() {println(testUnit(5,"abc"))
}private fun testUnit(age:Int,name:String) {}
输出:
kotlin.Unit
3.5 反引号的函数名
在函数名上面加一个反引号,kotlin支持这种写法,这样做的主要目的是为了和Java的交互性。Java和Kotlin是可以无缝调用的,但因为Java和Kotlin的关键字不同,可能一些方法名在Java是合法的,但到了Kotlin就变成非法,这时候就可以加反引号解决。
例如下面的Java代码,声明了一个is方法,这在Java里面是合法的,但如果在kotlin里面要调用这个方法就不行了,因为is在Kotlin里面是一个关键字。
public class Data {public static void is(){}
}
这时候在函数名上加一个反引号就可以解决这个问题。这样is就不被当作是关键字而可以在kotlin里面使用了。
//在kotlin中调用
Data.`is`()
有趣的是,加了反引号之后,方法名甚至可以写空格例如下面的代码。
private fun `first we calculate add`(a: Int,b:Int):Int{return a+b;
}private fun `second we calculate sub`(a: Int,b:Int):Int{return a-b;
}fun main() {val add= `first we calculate add`(1,2)val sub = `second we calculate sub`(1, 2)println("$add $sub")
}
用自然语言编程不再是梦。当然这个应该是用不太上,主要还是为了解决和Java的交换问题,写类似注释的方法名还是交给注释比较好。
3.6匿名内部类
我们举String的count方法为例,count方法有两个重载,第一个无参函数非常好理解,第二个重载声明如下,要求我们传入一个lambda表达式,这个表达式传入char,返回boolean(判断条件),最后整个函数返回一个int,也就是我们指定的char字符有多少个。
public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int
var count="Kotlining".count()var countI = "Kotlining".count({letter -> letter == 'i'} )println(count)println(countI)
输出
9
2
3.7 函数类型
这个和C语言的函数指针是非常像似的,但java是移除了这些特性的。
我们看下面的代码,第一次看这个代码可能非常的奇怪,看着像lambda表达式,又不完全是,其实这里的关键就是理解()->String的含义。这个语法是lambda表达式,但这里的真正含义是匿名内部类类型,并且这个匿名内部类返回String类型。顺理成章的,我们定义的变量result的类型也就变成了String类型。注意是一个类型声明,而不是lambda表达式实体,lambda表达式的实体是{}里面的内容。
var result:()->String={val animal="dog""This is $animal"}
看下和lambda表达式的对比:
下面是java的lambda表达式.一个非常明显的区别就是kotlin的匿名内部类没有return,而且在里面也是不可以写return的,这是因为他默认返回类型是表达式的最后一行。为了实现这个功能,就必须显示的声明类型,因为可能返回一个类对象。
()->{val animal="dog"return "This is $animal"}
当然也是可以带参数的。在()里面声明参数类型,在{}开头可以写具体名字。写法还是非常飘逸的。
val result2:(String,Int)->String={name,age->val animal="dog""This is $animal , name is $name , age is $age"}println(result2("tom",5))
输出:
This is dog , name is tom , age is 5
还有一种类型推断的写法,如下,参数我们还是要指定类型的,但返回值可以推断出来。感觉这种写法更简洁一点,前面的写法更标准一些。
val result4 = { name: String, age: Int ->val animal = "dog""This is $animal , name is $name , age is $age"}
3.8 it关键字
接着上小节,如果参数只有一个的时候,我们可以不写具体的参数名字,kotlin默认为我们提供了一个it关键字,可以直接使用这个关键字当参数变量名称。
val result3:(String)->String={val animal="dog""This is a $animal , name is $it."}println(result3("tom"))
输出:
This is a dog , name is tom.
3.9函数做为函数参数
下面这个函数的功能是显示学生信息,包括学生的姓名和身份证,第二个参数是一个函数类型,没错可以将一个函数做为参数传进来。这个函数可以合成学生的身份证,身份证由邮政编码,生日,编号构成。
private fun showStudentInfo(name: String, getId: (Int,Int,Int) -> String): String {//必须用大括号return "$name's id is ${getId(300027,20001212,1001)}"
}
var getId = { code: Int, birth: Int, num: Int ->"$code$birth$num"}println(showStudentInfo("Tom", getId))
输出:
Tom's id is 300027200012121001
其实这个写法非常的奇怪。声明一个函数然后又去调用,那干嘛不直接写一个函数呢?其实,上面的写法是不合理的,一般不会这么写,问题就出在var getId这个变量上,我们写了这个变量来引用函数类型,这是没有必要的,因为我们用函数类型的目的就是为了写匿名函数,取名字完全是多此一举。可以简化写成下面的样子。
println(showStudentInfo("Tom", { code, birth, num ->"$code$birth$num"}))
这样看起来就是非常简洁了。而且,kotlin有规定,如果只有一个函数类型,或者函数类型是最后一个,()可以省略。
函数类型是最后一个的情况:
println(showStudentInfo("Tom") { code, birth, num ->"$code$birth$num"})
只有一个函数类型做参数的时候
println(showStudentInfo { code, birth, num ->"$code$birth$num"})
这种写法一定要掌握,因为这个写法在kotlin里面是非常常见的。
这种写法一定要掌握,因为这个写法在kotlin里面是非常常见的。
这种写法一定要掌握,因为这个写法在kotlin里面是非常常见的。
3.10 内联函数
内联函数的主要用途就是为匿名函数提高性能。在调用下面的有函数类型做为参数的方法时,会使用到匿名内部类。第二个参数要求我们传入匿名内部类,对于编译器来说,匿名内部类的创建和普通类是一样的,但既然是匿名的,效率应该要更高写,如果也是和普通类一样创建,效率就比较低了。内联函数就是为了解决这个性能问题,那么是怎么解决的呢?答案是通过宏替换,如果你学过C语言,你就知道C语言的宏替换,内联函数也是一样的,通过宏替换,我们直接把匿名内部类的代码直接复制到调用的函数里面,这样就不需要创建类了,不需要创建类当然性能就提高了。
private fun showStudentInfo(name: String, getId: (Int,Int,Int) -> String): String {return xxx
}
使用方法就是直接添加一个inline关键字就可以了。
private inline fun showStudentInfo(name: String, getId: (Int,Int,Int) -> String): String {return xxx
}
3.11 函数引用
在调用含有函数类型的方法时,不光可以传入匿名内部类,也可以传通常的方法,这时候就需要用到函数引用。
例如下面的代码,foo方法的参数列表和showStudentInfo里面的getId函数类型的参数列表是一样的,这个时候可以把foo直接传给showStudentInfo。使用方法就是在::加普通函数名称。
private fun showStudentInfo( name:String, getId: (Int,Int,Int) -> String): String {//必须用大括号return "$name's id is ${getId(300027,20001212,1001)}"
}private fun foo( a:Int,b:Int,c:Int ): String {return "$a$b$c"
}println(showStudentInfo("Tom", ::foo))
输出:
id is 300027200012121001
3.12 函数类型做为返回类型
简单来说,就是一个函数返回另一个函数。什么?这有什么意义?如果有多个函数进行嵌套调用,那么就会形成函数之间的层层包含关系。这样的好处就是子函数可以共享父函数的变量,这种写法在脚本语言中是非常常见的,例如JavaScript。这样做的原因是脚本语言存在一个很大的问题,就是即使在不同的文件里面定义相同的变量名也会报错。因为脚本语言并没有像java这样有package和class的概念。kotlin也可以做为脚本语言。我们只能举个简单的例子来说明一下她的形式,理解的比较深还是需要大量的实践的。
看下面的代码,返回值是一个函数类型,传入一个String返回String。
private fun foo(a:Int):(String)->String{return {"$it"}
}
在main函数中执行,返回函数类型的变量bar,可以调用,传入"abc"返回"abc"
var bar = foo(1)println(bar.invoke("abc"))
输出:
abc
kotlin入门最容易教程一(最全,最详细)相关推荐
- 视频教程-Oracle数据库从入门到实用教程详解-Oracle
Oracle数据库从入门到实用教程详解 全栈工程师,2010年从事软件开发以及软件教育培训工作,至今将近十余年,在项目的开发,设计,到管理上积累了丰富的实战经验,教学风格上通俗易懂,问题解答环节一对一 ...
- 阿里架构师开源《Kotlin入门教程指南》+《高级Kotlin强化实战》
对于有Java基础的程序员来说,Kotlin是一门非常容易上手的编程语言,也是一门必须掌握的编程语言.Java代码在运行前需要编译生成一种特殊的class文件,然后Java虚拟机会识别并解释这些cla ...
- 关于 Kotlin 一系列的学习教程、文章。学好 Kotlin 从这里开始,争取做到最全、最详细。让没有编程经验的朋友也能通过这个系列教程用 Koltin 语言来开发项目
KotlinLearn 项目地址:Jetictors/KotlinLearn 简介: 这是一个关于 Kotlin 一系列的学习教程.文章.学好 Kotlin 从这里开始,争取做到最全.最详细.让没有编 ...
- Kotlin入门教程——目录索引
Kotlin是谷歌官方认可的Android开发语言,即将发布的Android Studio 3.0版本也会开始内置Kotlin,所以未来在App开发中Kotlin取代Java是大势所趋,就像当初And ...
- kotlin coroutines 协程教程-入门用法
kotlin coroutines 协程教程-入门用法 Coroutine 协程,是kotlin 上的一个轻量级的线程库,对比 java 的 Executor,主要有以下特点: 更轻量级的 api 实 ...
- Kotlin入门(24)如何自定义视图
Android提供了丰富多彩的视图与控件,已经能够满足大部分的业务需求,然而计划赶不上变化,总是有意料之外的情况需要特殊处理.比如PagerTabStrip无法在布局文件中指定文本大小和文本颜色,只能 ...
- Kotlin入门(8)空值的判断与处理
上一篇文章介绍了如何对循环语句进行操作,末尾还演示了发现空串时直接继续下一循环,只是在初始化字符串数组时使用了"val poem2Array:Array<String?> = * ...
- vue设置cookie的domain无效_【Vue.js入门到实战教程】16Tailwind 与 Bootstrap 的区别和使用入门...
来源 | https://xueyuanjun.com/post/22065我们知道,从 Laravel 8 开始,自带前端脚手架代码默认兼容 Tailwind CSS 框架,取代了之前的 Boots ...
- Kotlin入门(33)运用扩展属性
进行App开发的时候,使用震动器要在AndroidManifest.xml中加上如下权限: <!-- 震动 --><uses-permission android:name=&quo ...
- Kotlin入门(32)网络接口访问
手机上的资源毕竟有限,为了获取更丰富的信息,就得到辽阔的互联网大海上冲浪.对于App自身,也要经常与服务器交互,以便获取最新的数据显示到界面上.这个客户端与服务端之间的信息交互,基本使用HTTP协议进 ...
最新文章
- 在Ubuntu 14.04 64bit上安装Master PDF Editor 3.2.81
- 深度学习100例-卷积神经网络(CNN)彩色图片分类 | 第2天
- JZOJ 3815. 【NOIP2014模拟9.7】克卜勒
- DCMTK:修改DICOM文件的类
- 卡通渲染进阶 = toonlighting + outline + rimlighting + hair specular
- 学习vi和vim编辑器(8):全局替换(1)
- 基于SpringCloud实现Shard-Jdbc的分库分表模式,数据库扩容方案
- 华为鸿蒙系统耳机,华为鸿蒙系统真的来了,完整升级名单曝光!
- 在c语言中定义共用型数据类型的关键字是,C语言的关键字共有32个,根据关键字的作用,可分其为数据类型关键...
- Shell脚本学习-阶段十二-在CentOS 7上给一个网卡分配多个IP地址
- 【教程】如何正确的写一个Lemon/Cena的SPJ(special judge)
- Android6.0之前版本(AwesomePlayer)OMXCodec执行流程细节
- kali字典_Web渗透测试——暴力破解字典制作工具的使用2
- 手把手教你 如何安装 Ubuntu(乌班图)
- 结构体初始化、结构体指针、结构体数组
- cygwin 编译android,再次在 cygwin 下编译 Android toolchain
- [frida] 01_食用指南(持续更新)
- Trimmed 稳健均值估计与 中位数-中位数配对偏差法估计标准差——理论与 Python 实现
- 网站死链检查处理方法
- Layui form 表单验证lay-verify