按照国际惯例,学习一门新的语言一般都是从“Hello World”开始的,在这里也不例外,先看下 Java 中的 main
方法如何用 Kotlin 来表示java
fun main(args: Array<String>) {
println("Hello World")
}
复制代码
从这里能够看出 Kotlin 相比 Java 有几点不一样git
此外,Kotlin 的最新版本已经能够省略 main
方法的参数了github
在 Java 中,大部分的变量是可变的,意味着任何能够访问到这个变量的代码均可以去修改它。而在 Kotlin 中,变量能够分为 可变变量(var) 和 不可变变量(val) 两类编程
声明变量的关键字有两个:数组
不可变变量在赋值以后就不能再去改变它的状态了,所以不可变变量能够说是线程安全的,由于它们没法改变,全部线程访问到的对象都是同一个,所以也不须要去作访问控制,开发者应当尽量地使用不可变变量,这样可让代码更加接近函数式编程风格安全
此外,在 Kotlin 中一切都是对象,没有像 Java 中那样的原始基本类型,但 byte、char、integer、float 或者 boolean 等类型仍然有保留,可是所有都做为对象存在ide
看如下例子函数式编程
fun main(args: Array<String>) {
//只读变量即赋值后不能够改变值的变量,用 val 声明
//声明一个整数类型的不可变变量
val intValue: Int = 100
//声明一个双精度类型的可变变量
var doubleValue: Double = 100.0
}
复制代码
在声明变量时咱们一般不须要指明变量的类型,这能够由编译器根据上下文自动推导出来函数
fun main(args: Array<String>) {
//在声明变量时咱们一般不须要指明变量的类型,这能够由编译器根据上下文自动推导出来
val intValue = 100
var doubleValue = 100.0
//若是只读变量在声明时没有初始值,则必须指明变量类型
val intValue2: Int
intValue2 = 10
}
复制代码
与 Java 不一样,Kotlin 并不区分基本数据类型和它的包装类,在 Kotlin 中一切都是对象,能够在任何变量上调用其成员函数和属性学习
对于基本类型,Kotlin 相比 Java 有几点特殊的地方
//在 Kotlin 中,int、long、float 等类型仍然存在,可是是做为对象存在的
val intIndex: Int = 100
//等价于,编译器会自动进行类型推导
val intIndex = 100
//数字类型不会自动转型,必需要进行明确的类型转换
val doubleIndex: Double = intIndex.toDouble()
//如下代码会提示错误,须要进行明确的类型转换
//val doubleIndex: Double = intIndex
val intValue: Int = 1
val longValue: Long = 1
//如下代码会提示错误,由于二者的数据类型不一致,须要转换为同一类型后才能进行比较
//println(intValue == longValue)
//Char 不能直接做为数字来处理,须要主动转换
val ch: Char = 'c'
val charValue: Int = ch.toInt()
//如下代码会提示错误
//val charValue: Int = ch
//二进制
val value1 = 0b00101
//十六进制
val value2 = 0x123
复制代码
此外,Kotlin 的可空类型不能用 Java 的基本数据类型表示,由于 null 只能被存储在 Java 的引用类型的变量中,这意味着只要使用了基本数据类型的可空版本,它就会被编译成对应的包装类型
//基本数据类型
val intValue_1: Int = 200
//包装类
val intValue_2: Int? = intValue_1
val intValue_3: Int? = intValue_1
//== 比较的是数值相等性,所以结果是 true
println(intValue_2 == intValue_3)
//=== 比较的是引用是否相等,所以结果是 false
println(intValue_2 === intValue_3)
复制代码
若是 intValue_1 的值是100,就会发现 intValue_2 === intValue_3 的比较结果是 true,这就涉及到 Java 对包装类对象的重复使用问题了
Any 类型是 Kotlin 全部非空类型的超类型,包括像 Int 这样的基本数据类型
若是把基本数据类型的值赋给 Any 类型的变量,则会自动装箱
val any: Any = 100
println(any.javaClass) //class java.lang.Integer
复制代码
若是想要使变量能够存储包括 null 在内的全部可能的值,则须要使用 Any?
val any: Any? = null
复制代码
Kotlin 中的 Unit 类型相似于 Java 中的 void,能够用于函数没有返回值时的状况
fun check(): Unit {
}
//若是返回值为 Unit,则能够省略该声明
fun check() {
}
复制代码
Unit 是一个完备的类型,能够做为类型参数,但 void 不行
interface Test<T> {
fun test(): T
}
class NoResultClass : Test<Unit> {
//返回 Unit,但能够省略类型说明,函数也不须要显式地 return
override fun test() {
}
}
复制代码
Nothing 类型没有任何值,只有被当作函数返回值使用,或者被当作泛型函数返回值的类型参数使用时才会有意义,能够用 Nothing 来表示一个函数不会被正常终止,从而帮助编译器对代码进行诊断
编译器知道返回值为 Nothing 类型的函数从不正常终止,因此编译器会把 name1 的类型推断为非空,由于 name1 在为 null 时的分支处理会始终抛出异常
data class User(val name: String?)
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
fun main(args: Array<String>) {
val user = User("leavesC")
val name = user.name ?: fail("no name")
println(name) //leavesC
val user1 = User(null)
val name1 = user1.name ?: fail("no name")
println(name1.length) //IllegalStateException
}
复制代码
Kotlin 中的函数以关键字 fun 做为开头,函数名称紧随其后,再以后是用括号包裹起来的参数列表,若是函数有返回值,则再加上返回值类型,用一个冒号与参数列表隔开
//fun 用于表示声明一个函数,getNameLastChar 是函数名
//空括号表示该函数无传入参数,Char 表示函数的返回值类型是字符
fun getNameLastChar(): Char {
return name.get(name.length - 1)
}
复制代码
//带有两个不一样类型的参数,一个是 String 类型,一个是 Int 类型
//返回值为 Int 类型
fun test1(str: String, int: Int): Int {
return str.length + int
}
复制代码
此外,表达式函数体的返回值类型能够省略,返回值类型能够自动推断。对于有返回值的代码块函数,必须显式地写出返回类型和 return 语句
//getNameLastChar 函数的返回值类型以及 return 关键字是能够省略的
//返回值类型能够由编译器根据上下文进行推导
//所以,函数能够简写为如下形式
fun getNameLastChar() = name.get(name.length - 1)
复制代码
若是无返回值,则能够声明 Unit ,也能够省略 Unit
如下三种写法都是等价的
fun test(str: String, int: Int): Unit {
println(str.length + int)
}
fun test(str: String, int: Int) {
println(str.length + int)
}
fun test(str: String, int: Int) = println(str.length + int)
复制代码