[Kotlin]Kotlin学习笔记(一):环境搭建及Kotlin特色语法学习笔记

来源:互联网 发布:软件需求变更流程图 编辑:程序博客网 时间:2024/05/21 07:03

>Kotlin环境的搭建

    Kotlin是JetBrain公司推出的基于JVM的编程语言,个人感觉就是JAVA的Swift版本吧。加上被google宣布为android的官方支持开发语言,未来使用的空间和必要性不言而喻。

    由于是JetBrain公司推出的公司,其名牌IDE产品——IntelliJ IDEA,自带运行Kotlin所需要的内容,开发者所需要做的只是去下载一个JDK,并在新建工程时指定JDK目录位置即可。

    此处提到的、值得一知的搭建Kotlin环境,主要针对以下两种编译器:

1.Eclipse:

点击Help-Eclipse Marketplace-搜索Kotlin:

如果你之前已经配置好JDK位置了,直接New一个Kotlin Project,并建立一个Kotlin Class/File就可以开始测试Kotlin了:

fun main(args: Array<String>){    println("Hello Kotlin World!")}
2.Android Studio:

点击File-Setting-Plugins-搜索Kotlin-安装Kotlin语言包-重启Android Studio
新建一个Android Studio工程,在project-build.gradle中手动指定一下Kotlin版本:

ext.kotlin_version = '1.0.3'
在module-build.gradle配置Kotlin插件和类库:

apply plugin: 'kotlin-android'apply plugin: 'kotlin-android-extensions'compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

>Kotlin学习笔记:基础及特色语法研究

1.注释及语句

//单行注释/*多行注释*/

同时,Kotlin不再强调句尾需要 ; 作为语句间的区分,但你仍然可以用分号来对同一行两个语句进行手动区分,如:

val a:Int=7 ; val b:Int = 8

2.字符串模板

Kotlin支持类似XML中的$变量:

$varName //varName是任意变量名${varName.funcation()}
如对于Int值a和类Base中的输出类名的函数boo(),测试以下代码,最后两行会输出的值为:

val a:Int = 7val b:Base = Base()println("Line1:a = $a")//输出 Line1:a = 7println("Line2:b.boo() = ${b.boo()}")//输出 Line2:b.boo() = Base
3.区间

区间主要有以下几个写法:(基于关键字 in    ..    downTo     step    until    !in

i in 3 .. 6 // 3<=i && i<=6i in 3 .. 6 step 2 // i=3 i=5i in 6 downTo 3 // i=6 5 4 3i in 3 until 6 // 3<=i && i<6 
  • .. 主要用于标注区间,对于a .. b,其相当于[a,b],也就是for(i=a;i<=b;i+=1);
  • step 主要用于标注前进的步长,对于上面第二句代码,相当于for(i=3;i<=6;i+=2)。同时,要注意步长必须为正数
  • downTo 表示逆序递减,对于上面第三句代码,相当于for(i=6;i>=3;i--),同样,可以用step修饰,如:i in 6 downTo 3 step 2;
  • until 表示一个去尾元素,如上面第四句代码,相当于for(i=3;i<6;i++);
  • in 和 !in 表示前导元素i是否在后续区间中

一定有人有疑问,基于这样的区间,对于for(int i=3;i<=6;i*=2)该怎么表示?

 答案是没法表示。for语句在kotlin中用作迭代,不是基于条件转移控制的语句。要实现上面的那个语句,需要用到while。待会儿再细讲。

区间(a .. b)的本质是创建一个数列,for中的" i in 区间 ",实际上是在进行一个区间数列的迭代,所以诸如i*=2之类的操作是没法进行的。

顺便说一下,其实对于C语言中的for,我一直觉得跟while完全没区别,while能做到的for也能做到,while简直冗余。


还有人要问,downTo的区间也是[a,b],那怎么实现[a,b)?可以用until修饰吗?

答案是依旧不行。只能手动写成 [a,b-1]了。

另外要注意数列必须是正序的,除非使用了downTo,如:

if(i in 8 .. 1)println("这句话永远不会输出")

还有一些问题,区间可以用来做什么呢?

其一是:条件判断,如:

if(a !in 7 .. 10)println("yes")//a的值不在[7,10]之间时,输出字符串"yes"
那么,下面这个句子到底会输出什么呢?
var a:Int = 7if(a in 5 .. 9 step 3 )println("$a 会输出吗?")
答案是不会输出,因为7+3 > 9,已经超出了这个区间,所以if判断为false。
其二是:生成数列

对于这个语句:

println(3 .. 10 step 2)//输出为 3 .. 9 step 2
输出:

而生成数列最大的用处就是用于for循环的迭代了。这个简单,就不再说了。

其三是:字符串包含性判断

if("Hello" in "Hello world".."=w=") println("yes")//输出yes

4.类型判断

Kotlin提供了对于一个对象的类型判断关键字 is 和 !is。注意,子类型的对象同时也是父类型的对象(详见下)

obj is class
对于Base的对象base,有如下语句;另,Child是Base的子类型,Father是Base的父类型
if(base is Father) println("父")if(base is Base) println("自己")if(base is Child) println("儿")
输出结果为:

5.函数定义

语法为:

[权限修饰符,默认为public] fun 函数名(参数:参数类型){//函数体}
当然这个很简单,其匿名形式为:

[权限修饰符] fun (参数:参数类型) : 返回值类型 = 函数体
传参可以是变长类型,利用vararg修饰,如下面这个函数:

fun varFun(vararg v:Int){     for(vt in v){          println(vt)     }}varFun(6,6,6,6,8)//输出6 6 6 6 8

6.Lambda表达式(&& 匿名Lambda函数)

比较下面这三个函数:


Lambda的匿名体现在对函数声明的匿名化,从原始函数add开始,不断简化,到了add4,甚至只剩下函数体({}间的部分)

Lambda的语法为:

定义lambda表达式vaName:(参数类型) ->返回类型 = { 参数 -> 返回内容}定义lambda表达式varName = { 参数:类型 -> 返回内容}//此时返回内容的类型会自动识别
注意,{}里的才叫做Lambda表达式。左边等号前面的只是一种定义形式,方便调用而已(如果“完全匿名”,就只能在写出的地方使用一次,而无法全局调用)。
如下面这个句子里,直接使用了Lambda表达式而不使用其定义:

fun max(S:Boolean , { a , b -> a < b }){}
这个语句中的{ a, b -> a<b }本身就是一个匿名的Lambda表达式,整个max函数是一个传参带有函数返回值的高阶函数,其完全体形式应为:

fun max(S:Boolean , compare(a:Int , b:Int)){}fun compare(a:Int , b:Int){    return a < b}
这样说明应该很清楚了。

对了,上图中的add2,改成 fun ( x:Int , y:Int ):Int = x+y,其实就是add的匿名函数

7.字符串拼接

Kotlin支持Java中字符串间的+拼接,同时支持一种多行拼写:""" ,例子:

val ss3:String = """    |第一行    |第二行222    |第三行    &第四行|            |第五行    """.trimMargin()    println(ss3)

输出结果为:

第一行第二行222第三行    &第四行|第五行
trimMargin(String 修建关键字)可以修建掉修建关键字及每行前的空格(保证对齐)。默认使用"|"作为修建关键字。

8.位操作符及装箱等操作

shl(bits) – 左移位 (Java <<)shr(bits) – 右移位 (Java >>)ushr(bits) – 无符号右移位 (Java’s >>>)ushl(bits) – 无符号左移位 (Java’s <<<)and(bits) – 与操作or(bits) – 或xor(bits) – 异或inv() – 位取反===  – 地址比较== – 值比较

网上关于===的“封箱”,是一个套用自官网的说明。经过我对JVM的回忆和理解,我觉得这个例子有问题,于是我找到了这么一个trap:

    val b:Int = 5    val b1:Int? = b    val b11:Int? = b    println(b1 === b11) // 注意这里打印的是 'true'    val a: Int = 10000    val a1: Int? =a    val a11: Int? = a    println (a1 === a11 ) //注意这里打印的是 'false'
如图所示:

我看了大部分的中文资料,都提到装箱的问题。但是我去看了一下源码,才知道他们都是扯淡。只要把Int的值换成128一下的整型数,都不会进行所谓的“装箱”处理。

这分明是一个JVM问题,涉及到缓存池,大部分教程在这里都没有说明白,甚至就是直接引用官网的说明文档。

这是这个问题的具体解释:JVM把[-128,127]的所有数字全部缓存了,任何指向这个范围的对象,都不可能被另外创建,又何谈“装箱”