准备工作
- 下载安装kotlin编译器,记录此笔记时的版本是v1.2.10,目前最新发布版本是v2.1.10
- 解压下载的安装包,配置环境变量指向bin目录(官方指导).
如果不想在本地安装环境,也可以使用在线编辑器
尝试编写第一个helloWorld
- 新建一个名为
hello.kt
的文件,内容如下:
fun main(args: Array<String>) {
println("Hello, World!")
}
- 执行以下命令将kotlin编译生成jar:
kotlinc hello.kt -include-runtime -d hello.jar
-d
参数用于指定生成的文件名.-include-runtime
参数指定将kotlin运行时需要的依赖库编译进包.
- 运行jar
java -jar hello.jar
此时你可以看到命令窗口下出现了熟悉的"helloWorld!"
Hello, World!
开发工具
-
IntelliJ IDEA的Kotlin插件是和语言同步开发的,是可用功能最全的开发环境.InterlliJ IDEA15及以后的版本不需要额外设置,Kotlin插件可以开箱即用.你可以选择免费开源的IntelliJ IDEA Community版,也可以选择IntelliJ IDEA Ultimate版本.在"New Project"对话框中选择"Kotlin",然后就可以开始工作了.(参考材料:官方说明-内有下载链接)
-
如果你用的是Android Studio,可以从"plug-in manager"(插件管理器)中安装Kotlin插件,打开"setting"(设置)=>“Plugins”(插件)=>“Install JetBrains Plugin”(安装JetBrains插件)=>“Kotlin”,就可以开始工作啦.
-
Eclipse同样可以使用kotlin,Kotlin的Eclipse插件提供了必要的IDE功能,如导航和代码补全.可以通过Eclipse Marketplace中找到,选择"Help"=>“Eclipse Marketplace”,搜索"kotlin"即可.
-
最简单的方式,就是直接使用在线playground,不需要安装任何环境和配置就可以在线编写编译及运行Kotlin小程序.在线playground
基本语法差异(与java对比)
- 声明一个函数使用关键字:
fun
,如上面的helloWorld. - 数组就是类,Kotlin没有声明数组类型的特殊语法.如:
Array<String>
println
代替了System.out.println
.- 代码行结尾不需要
;
. - 参数及类型用
:
隔开,函数返回类型写在参数列表之后.如:fun max(a:int,b:int):Int{
.
变量
定义变量使用关键字+变量名+类型(也可不加).
如:
val question = "The Ultimate Question of Life,the Universe,andEverything"
var answer = 42
var answer: Int //如果没有初始化,要显示指定类型.
如果你不指定类型,编译器会自动分析初始经表达式的值,自动推导出变量类型.
可变变量和不可变变量
val
:不可变引用,对应java的final. --应尽可能地使用它来场景所有的kotlin变量.
尽管val引用自身是不可变的,但它指向的对象可能是可变的.如:
var languages = arrayListOf("Java")
languages.add("Kotlin")
var
:可变引用.
字符串模板
先看个例子:
fun main(args:Array<String>){
val name = if(args.size > 0) args[0] else "Kotlin"
println("Hello,$name!")
}
以上使用了$
字符将变量转义输出,等效于java中的:
"Hello,"+name+"!"
如果需要在字符串中输出*$*字符,需要对它进行转义,如:
println("\$x")
将会输出:
$x
涉及较复杂的表达式时,需要将表达式用{}
括起来:
println("Hello,${args[0]}!")
在花括号内,还可以嵌套使用双引号
println("Hello,${if(args.size>0) args[0] else "someone"}!")
类和属性
类中声明只读属性和可写属性使用关键字val
和var
来区分:
class Person(
val name : String,// 只读属性,生成一个字段和一个简单的getter
var isMarried: Boolean //可写属性,生成一个字符,一个getter和一个setter
)
使用属性:
fun main(args: Array<String>) {
println("Hello, world!")
val person = Person("lqq",true) //调用构造方法不需要使用new关键字
println("Hello,"+person.name) //可以直接访问属性,但实际调用的是getter
println("Hello,${person.name}!")
}
自定义访问器:
fun main(args: Array<String>) {
val rec = Rectangle(3,3)
println(rec.isSquare)
}
class Rectangle(val height: Int, val width: Int){
val isSquare: Boolean
get(){
return height == width
}
//也可以写为:
//get() = height == width
}
目录和包
- Kotlin不区分导入的是类还是函数,可以直接导入函数
package geometry.example
import geometry.shaes.createRandomRectangle
fun main(args: Array<String>){
println(createRandomRectangl().isSquare)
}
- 包层级结构可以不需要遵循目录层级结构
geometry
|--example.kt <=包geometry.example
|--shapes.kt <=包geometry.shapes
表示和处理选择
枚举
Kotlin中这是极少数比Java使用了更多关键字的例子,使用了enum
和class
两个关键字:
enum class Color{
RED,ORANGE,YELLOW,GREEN
}
声明一个带属性的枚举类
enum class Color(
val r: Int,val g: Int,val b: Int){
RED(255,0,0),ORANGE(255,165,0),
YELLOW(255,255,0); //这里必须要有分号,这是Kotlin语法中唯一必须使用分号的地方.
fun rgb() = (r*256+g)*256+b //给枚举定义一个方法
}
when
使用when
来处理枚举类.
与Java不同,不需要为每个分支都写上break语句.
fun getMnemonic(color:Color) = //直接返回一个when表达式
when(color){ //如果颜色和枚举常量相等就返回对应字符串
Color.RED -> "Richard"
Color.ORANGE -> "OF"
Color.YELLOW -> "York"
Color.GREEN -> "Gave"
Color.BLUE -> "Battle"
...
}
>>> println(geMnemonic(Color.BLUE))
Battle
一个分支上合并多个选项,只需要用,
隔开
fun getWarmth(color:Color) = when(color){
Color.RED,Color.ORANGE ->"warm"
Color.GREEN -> "neutral"
}
在when
中使用任意对象
fun mix(c1:Color,c2:Color)=
when(setOf(c1,c2)){
setOf(RED,YELLOW) -> ORANGE
setOf(YELLOW,BLUE) -> GREEN
else -> throw Exception("Dirty color")
}
以上模拟了调色板的方法,当调用参数与分支条件相等时可以得到对应的返回.都不满足时返回返回else分支结果.
以上写法也可以改为不带参数的when(优点:不会创建额外对象,但会更难理解):
fun mix(c1:Color,c2:Color)=
when{
(c1 == RED && c2 == YELLOW) || c1 == YELLOW && C2 == RED -> ORANGE
else -> throw Exception("Dirty color")
}
智能转换
在Java中,需要通过instanceOf来检查一个变量是否属于某个类型,使用时还需要显示的转换,如:
if( e instanceOf Sum){
Sum s = (Sum)e;
return s.left;
}
而在kotlin中,通过一次is检查后,即可直接使用(编译器自动执行了类型转换):
if(e is Sum){
return e.left
}
代码块做为"if"和"when"的分支
if
和when
都可以使用代码块作为分支体.在这种情况下,代码块中的最后一个表达式就是返回的结果.
fun evalWithLoggin(e:Expr):Int =
when(e){
is Num ->{
println("num:${e.value}")
e.value //如果e的类型是Num就会返回这个表达式
}
is Sum ->{
val left = evalWithLogging(e.left)
val right = evalWithLogging(e.right)
left+right //如果e的类型为Sum就会返回这个表达式
}
else -> throw IllegalArgumentException("Unknown expression")
}
迭代数字:区间和数列
kotlin中可以使用..
来表示区间
//闭区间
for(i in 1..100){
println(i)
}
//补充:开区间
for(i in 0 until 10){
println(i)
}
倒序迭代:
for(i in 100 downTo 1 step 2){
println(i)
}