Kotilin是官方推荐的第一语言,所以本章大概记录一下他和别的语言的区别和特点。
运行环境
Kotilin可以使用InterliJIDEA,是JetBrains的期间IDE来运行。或者使用try.lotilinlang.org在线运行。我比较懒还是在AS上运行就可以了。
第一次写Kotilin代码
我们还是在上一节的HelloWorld里写代码运行吧。我们在MainActivity位置,鼠标右键添加Kotilin File/Class,我们建立一个.kt的文件,我这里取名Comm.kt
我写入代码如下:
package com.example.helloworld
import android.util.Log
fun main(){
println("main run");
Log.d("first","main run");
}
增加了main函数,你会发现函数前面出现一个运行的绿色箭头,如下图
点击箭头就可以运行程序了
我们在输出窗口Run里可以看到运行结果,println输出了main run,而Log函数报错了,因为我们运行的这段Kotlin代码和Android无关。这就是在AS里单独运行Kotlin的方法,后面都按照这个来进行。
上一章和本章的代码我都加了分号,Kotilin是不用加分号的,可能C#写习惯了。
变量声明
val abc = 10 //val是不可变的的变量
var abc = 10 //var是可变变量
val abc : Int = 10 // 显示声明了变量类型
函数声明
import kotlin.math.max
fun main(){
println("main run")
//Log.d("first","main run")
println("max : "+methodName(1,2))
println("max2 : "+methodName(3,4))
}
//一般的书写
fun methodName(param1 : Int, param2 : Int) : Int
{
return max(param1,param2)
}
//特殊的书写
fun methodName2(param1 : Int, param2 : Int) = kotlin.math.max(param1,param2)
max引用了math库,可以鼠标悬浮在max上,点击导入。
条件
//普通用法
if(2>1)
{
println(" > ")
}
else
{
println(" < ")
}
//if可以赋值
var abc = if(2>1) 2 else 1
println("abc :"+abc)
//if赋值可以直接给函数当返回值
println("methodName3 :"+methodName3(5,6))
fun methodName3(param1 : Int, param2 : Int) = if(param1>param2) 2 else 1
when
这里我们还是写一个特殊的写法。
println("abc :"+methodName4("Li"))
fun methodName4(name:String) = when(name)
{
"Liu" -> 88
"Mao" -> 78
"Li" -> 99
else -> 0
}
循环
//循环从0到10(包含10)11个
for(i in 0..10)
{
println("for1:"+i)
}
//循环0到10,不包含10
val count = 0 until 10 //0-9
for(i in count)
{
println("for2:"+i)
}
//每次加2
for(i in count step 2)
{
println("for3:"+i)
}
//降序(从10到0)11个
for(i in 10 downTo 0)
{
println("for4:"+i)
}
执行结果
for1:0
for1:1
for1:2
for1:3
for1:4
for1:5
for1:6
for1:7
for1:8
for1:9
for1:10
for2:0
for2:1
for2:2
for2:3
for2:4
for2:5
for2:6
for2:7
for2:8
for2:9
for3:0
for3:2
for3:4
for3:6
for3:8
for4:10
for4:9
for4:8
for4:7
for4:6
for4:5
for4:4
for4:3
for4:2
for4:1
for4:0
类的使用
基本使用
class FirstRun {
var name = "" //必须初始化
fun run()
{
println("run : "+name)
}
}
调用缺少了new关键字,调用构造函数表示new
val obj = FirstRun()
obj.name = "Jason"
obj.run()
继承
被继承的类要加open关键字,类似于val一样,继承可以传递主构造函数的参数。
package com.example.helloworld
open class FirstRun(val nm:String)
{
var name = "" //必须初始化
init //init这里是主构造函数
{
name = nm
}
open fun run()
{
println("run : "+name)
}
}
//这里继承了父类,并且传入了构造函数的参数nm,注意nm不用加val。
class SecRun(val _t:Int,nm:String) : FirstRun(nm)
{
var t = 0//必须初始化
init
{
t = _t
}
override fun run() //override的父类函数必须要加open关键字
{
super.run()
println("run : "+name+",t:"+t)
}
}
val obj = SecRun(10 , "Jason")
obj.run()
运行结果:
run : Jason
run : Jason,t:10
次构造函数
constructor
package com.example.helloworld
open class FirstRun(val nm:String)
{
var name = "" //必须初始化
init //init这里是主构造函数
{
name = nm
}
open fun run()
{
println("run : "+name)
}
}
//这里继承了父类,并且传入了构造函数的参数nm,注意nm不用加val。
class SecRun(val _t:Int,nm:String) : FirstRun(nm)
{
var t = 0//必须初始化
init //init这里是主构造函数
{
t = _t
name = nm
}
constructor(nm:String) : this(
0,nm
)
constructor() : this(
0,""
)
override fun run() //override的父类函数必须要加open关键字
{
println("run : "+name+",t:"+t)
}
}
fun main(){
val obj1 = SecRun()
val obj2 = SecRun("Jason")
var obj3 = SecRun(3,"Jason")
obj1.run()
obj2.run()
obj3.run()
}
运行结果:
run : ,t:0
run : Jason,t:0
run : Jason,t:3
这样增加了两种次构造函数,这样就可以通过三种方式来构造函数了。
接口
class FirstRun() : Walk
{
var name = "Jason" //必须初始化
fun run()
{
println("run : "+name)
}
override fun walk1() {
println("walk1 : "+name)
}
}
interface Walk
{
fun walk1()
fun walk2(){ println("walk2") } //默认实现
}
fun main(){
val obj1 = FirstRun()
obj1.walk1()
obj1.walk2()
}
接口Walk两个实现,walk2有默认实现,walk1没有,所以必须要写walk1的实现。
函数修饰符
- public(所有类可见,默认没有写就是public)
- private (私有本函数)
- protected(当前类和子类)
- internal(模块内部调用)
数据类
数据类定义很简单
data class phone(val brand:String,val price:Int)
上面定义了一个手机,有品牌和价格。
fun main(){
val phone1 = phone("MI13",2888)
val phone2 = phone("MI13",2888)
println(phone1)
println("phone1 == phone2 ? "+(phone1 == phone2))
}
输出结果:
phone(brand=MI13, price=2888)
phone1 == phone2 ? true
单例类
一般全局只希望有一个实例化的某个类会使用单例类,其他语言需要用static 关键字定义instance来调用。Kotlin更简单。
object SingleClass
{
fun Do(){ println("do") }
}
fun main(){
SingleClass.Do()
}
只用添加object就可以了,看上去好像是静态的,其实Kotlin内部创建了一个单例。
拉姆达
下面是几个Kotlin的Lambda用法。
- 集合创建法
package com.example.helloworld
import android.util.Log
import kotlin.math.max
fun main(){
val lista = listOf(1,2,3,2,"a","b") //创建不可变集合
for (one in lista)
{
println(one)
}
println("------华丽的分割线-------")
val listb = setOf(1,2,3,2,"a","b") //创建不可变,不可重复集合
for (one in listb)
{
println(one)
}
println("------华丽的分割线-------")
val listc = mutableListOf(1,2,3,"a","b") //可变集合
listc.add("c")
for (one in listc)
{
println(one)
}
println("------华丽的分割线-------")
val mapa = mapOf("Mi" to 1,"Apple" to 2,3 to 3) //类似字典类型, mutableMapOf对应是可变的
for (one in mapa)
{
println(one)
}
}
运行结果
1
2
3
2
a
b
------华丽的分割线-------
1
2
3
a
b
------华丽的分割线-------
1
2
3
a
b
c
------华丽的分割线-------
Mi=1
Apple=2
3=3
- 拉姆达函数用法
{ 参数1:参数类型,参数2:参数类型 -> 函数体 }
fun main(){
val lista = listOf("Apple", "Banana" , "Orange" ,"Pineapple") //创建不可变集合
val x1 = lista.maxOf() { it.length }
println(x1)
val x2 = lista.filter { it.length > 5 }.map { it.uppercase() }
println(x2)
}
结果
9
[BANANA, ORANGE, PINEAPPLE]
Java函数的使用
假设有Java接口
public interface Runnable {
void run();
}
Kotlin调用
Thread(object : Runnable {
override fun run() {
println("running")
}
}).start();
我们创建了一个Runnable接口的匿名类示例,并调用。
这个Lambda是单参数,还可以简化成:
Thread { println("running") }.start()
Kotlin可能会经常调用Java接口,例如常用的。
button.setOnClickListener{}
空指针检查
fun doit (firstrun :FirstRun?)
{
if( firstrun != null)
{
firstrun.run()
}
}
一般Kotlin一般不允许有空,一般变量都有默认值,如果非要传递空,需要添加问号
判空辅助工具
- 操作符:?.
if(abc != null) abc.run()
可以写作
abc?.run()
- 操作符:?:
val c = a?:b
//如果a不是null,c=a,否则c=b
- 操作符:!!
var myname : String? = null
fun main(){
myname = "Jason"
run()
}
fun run()
{
val str = myname!!.uppercase()
println(str)
}
因为myname是可能为空的,如果run函数里没有!!,编译器会不让通过的,因为可能有风险某人直接调用run函数导致问题。所以!!操作符就好像你给编译器说,我保证这里没问题,绝对不会为空。这就是一个潜在的风险。
把上面的函数写成这样都是编译器不能通过的。
fun run()
{
if(myname != null)
{
val str = myname.uppercase()
println(str)
}
}
let函数
class Walk
{
fun run1(){}
fun run2(){}
fun run3(){}
}
fun main(){
val wk = Walk()
doWalk(wk)
}
fun doWalk(wk:Walk?)
{
wk?.run1()
wk?.run2()
wk?.run3()
}
这个doWalk函数里进行了3次?.操作,相当于判断了3次是否为空,这里可以用let函数替换。
fun doWalk(wk:Walk?)
{
wk?.let { work ->
work.run1()
work.run2()
work.run3()
}
}
小技巧
字符串
val who : String ="Jason"
println("hello : ${who} , byebye !")
hello : Jason , byebye !
默认参数
函数可以默认参数,甚至不用是最后几个有默认值,我们可以采用键值的放置传入函数,如下:
fun main(){
run(p3 = 2.5f, p2 = 90)
}
fun run(p1:String = "Jason",p2:Int,p3:Float=1.7f)
{
println(p1)
println(p2)
println(p3)
}
Jason
90
2.5
语法学习先到这里有个大概的了解,剩下的在工作和学习种再慢慢积累吧。
参考
《第一行代码》Android第三版