本文更偏向于有一定java基础的人学习,主要区分Kotlin 语言和java的区别。
当然,没有java基础您也可以学习Kotlin,请跳转 :Kotlin 零基础入门
如果不想配置Kotlin环境:Kotlin在线编程
Kotlin 可以编译成Java字节码,也可以编译成 JavaScript。
Kotlin 程序文件以 .kt 结尾,如:hello.kt 、app.kt。
Kotlin 命令行编译工具下载地址:Kotlin v1.1.2
1、行末分号可以省略,
2、变量、参数、方法返回的类型写在冒号后面,
3、创建对象不用new,
4、注释和java一样,
5、$p拼接字符串。
package hello // 可选的包头
fun main(args: Array<String>) { // 包级可见的函数,args 参数,Array 参数类型
println("Hello World!")
val s = "字符串"
val str = "$s.length is ${s.length}" // 求值结果为 "runoob.length is 6"
println(str)
val price = "${'$'}9.99"
println(price) // 结果为 $9.99
}
fun sum(a: Int, b: Int): Int { // Int 参数,返回值 Int
return a + b
}
public fun sum(a: Int, b: Int): Int = a + b // public 方法则必须明确写出返回类型
class Greeter(val name: String) {
fun greet() {
println("Hello, $name") // 用$拼接字符串
}
}
fun gg(): Unit { // Unit 无返回值,相当于void,也可以省略
Greeter("World!").greet() // 创建一个对象不用 new 关键字
}
var 可修改变量、val 不可修改变量
val a: Int = 1
val b = 1 // 系统自动推断变量类型为Int
val c: Int // 如果不在声明时初始化则必须提供变量类型
c = 1 // 明确赋值
var x = 5 // 系统自动推断变量类型为Int
x += 1 // 变量可修改
vararg 可变产长参数
fun vars(vararg v:Int){
for(vt in v){
print(vt)
}
}
fun main(args: Array<String>) {
vars(1,2,3,4,5) // 输出12345
}
fun main(args: Array<String>) {
val sumLambda: (Int, Int) -> Int = {x,y -> x+y}
println(sumLambda(1,2)) // 输出 3
}
//类型后面加?表示可为空
var age: String? = "23"
//抛出空指针异常
val ages = age!!.toInt()
//不做处理返回 null
val ages1 = age?.toInt()
//age为空返回-1
val ages2 = age?.toInt() ?: -1
当一个引用可能为 null 值时, 对应的类型声明必须明确地标记为可为 null。
当 str 中的字符串内容不是一个整数时, 返回 null
fun parseInt(str: String): Int? {
return str.toIntOrNull()
}
fun getStringLength(obj: Any): Int? {
if (obj is String) { // 单行if,{}可以省略
// 做过类型判断以后,obj会被系统自动转换为String类型
return obj.length
}
//在这里还有一种方法,与Java中instanceof不同,使用!is
// if (obj !is String){
// // XXX
// }
// 这里的obj仍然是Any类型的引用
return null
}
Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等。不同于 Java 的是,字符不属于数值类型,是一个独立的数据类型。
字面量:
1、长整型以大写的 L 结尾:123L
2、16 进制以 0x 开头:0x0F
3、2 进制以 0b 开头:0b00001011
4、注意:8进制不支持
5、Doubles 默认写法: 123.5, 123.5e10
6、Floats 使用 f 或者 F 后缀:123.5f
7、数字中可以使用下划线,使数字更易读
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
在 Kotlin 中,三个等号, 表示比较对象地址,两个等号表示比较两个值大小。
Byte、Short、Int等这些基本类型也有对象地址。
println(a === a) // true,值相等,对象地址相等
toByte()、toShort()、toInt()、toLong()等方法用于类型间转换。
val b: Byte = 1
val i: Int = b.toInt()
Char 不能直接和数字操作,Char 必需是单引号 ’ 包含起来
fun check(c: Char) {
println(c == 1) // false
println(c == '1') // true
}
多行字符串可以用三个引号
fun main(args: Array<String>) {
val text = """
|第一行
|第二行
|第三行
|第四行
""".trimMargin() // trimMargin() 方法删除多余的空白
println(text)
}
fun decimalDigitValue(c: Char): Int {
if (c !in '0'..'9')
throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt()
}
fun main(args: Array<String>) {
//[1,2,3]
val a = arrayOf(1, 2, 3)
//[0,2,4]
val b = Array(3, { i -> (i * 2) })
//读取数组内容
println(a[0]) // 输出结果:1
println(b[1]) // 输出结果:2
}
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// 作为表达式
val max = if (a > b) a else b
val max = if (a > b) {
print("Choose a")
a
} else {
print("Choose b")
b
}
when类似 switch
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // 注意这个块
print("x 不是 1 ,也不是 2")
}
}
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
for循环
// 迭代器
for (item in collection) print(item)
for (item: Int in ints) {
// ……
}
// list
for (i in array.indices) {
print(array[i])
}
fun main(args: Array<String>) {
val items = listOf("apple", "banana", "kiwi")
for (item in items) {
println(item)
}
for (index in items.indices) {
println("item at $index is ${items[index]}")
}
}
在循环中 Kotlin 支持传统的 break 和 continue 操作符。
return 允许我们从外层函数返回,
从 lambda 表达式中返回,我们必须给它加标签并用以限制 return。
// return结束整个foo
fun foo() {
ints.forEach {
if (it == 0) return
print(it)
}
}
// return结束forEach
fun foo() {
ints.forEach lit@ {
if (it == 0) return@lit
print(it)
}
}
// 函数名也是一个标签
fun foo() {
ints.forEach {
if (it == 0) return@forEach
print(it)
}
}
当要返一个回值的时候,解析器优先选用标签限制的 return
return@a 1
class Baidu {
var name: String = "百度"
var url: String = "www.baidu.com"
var city: String = "北京"
}
val site = Runoob()
println(site.name)
// constructor主构造器,这个关键字可以省略
class Person constructor(firstName: String) {}
getter 和 setter 都是可选
var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法
var initialized = 1 // 类型为 Int, 默认实现了 getter 和 setter
val simple: Int? // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化
val inferredType = 1 // 类型为 Int 类型,默认实现 getter
实例
class Person {
var lastName: String = "zhang"
get() = field.toUpperCase() // 将变量赋值后转换为大写
set
var no: Int = 100
get() = field // 后端变量
set(value) {
if (value < 10) { // 如果传入的值小于 10 返回该值
field = value
} else {
field = -1 // 如果传入的值大于等于 10 返回 -1
}
}
var heiht: Float = 145.4f
private set
}
// 测试
fun main(args: Array<String>) {
var person: Person = Person()
person.lastName = "wang"
println("lastName:${person.lastName}")
person.no = 9
println("no:${person.no}")
person.no = 20
println("no:${person.no}")
}
field 后端变量
field 关键词只能用于属性的访问器
var no: Int = 100
get() = field // 后端变量
set(value) {
if (value < 10) { // 如果传入的值小于 10 返回该值
field = value
} else {
field = -1 // 如果传入的值大于等于 10 返回 -1
}
}
init 关键字初始化代码段
class Person constructor(firstName: String) {
init {
println("FirstName is $firstName")
}
}
二级构造函数
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
// this调用主构造函数的name
class Person(val name: String) {
constructor (name: String, age:Int) : this(name) {
// 初始化...
}
}
abstract抽象类
如果一个类要被继承,可以使用 open 关键字进行修饰。
open class Base {
open fun f() {}
}
abstract class Derived : Base() {
override abstract fun f()
}
内部类使用 inner 关键字来表示。
内部类会带有一个对外部类的对象的引用,所以内部类可以访问外部类成员属性和成员函数。
class Outer {
private val bar: Int = 1
var v = "成员属性"
/**嵌套内部类**/
inner class Inner {
fun foo() = bar // 访问外部类成员
fun innerTest() {
var o = this@Outer //获取外部类的成员变量
println("内部类可以引用外部类的成员,例如:" + o.v)
}
}
}
fun main(args: Array<String>) {
val demo = Outer().Inner().foo()
println(demo) // 1
val demo2 = Outer().Inner().innerTest()
println(demo2) // 内部类可以引用外部类的成员,例如:成员属性
}
interface 与 匿名内部类
class Test {
var v = "成员属性"
fun setInterFace(test: TestInterFace) {
test.test()
}
}
/**
* 定义接口
*/
interface TestInterFace {
fun test()
}
fun main(args: Array<String>) {
var test = Test()
/**
* 采用对象表达式来创建接口对象,即匿名内部类的实例。
*/
test.setInterFace(object : TestInterFace {
override fun test() {
println("对象表达式创建匿名内部类的实例")
}
})
}
类的修饰符
abstract // 抽象类
final // 类不可继承,默认属性
enum // 枚举类
open // 类可继承,类默认是final的
annotation // 注解类
private // 仅在同一个文件中可见
protected // 同一个文件中或子类可见
public // 所有调用的地方都可见
internal // 同一个模块中可见
属性重写使用 override 关键字
open class Foo {
open val x: Int get { …… }
}
class Bar1 : Foo() {
override val x: Int = ……
}
扩展函数
class User(var name:String)
/**扩展函数**/
fun User.Print(){
print("用户名 $name")
}
fun main(arg:Array<String>){
var user = User("Runoob")
user.Print()
}
伴生对象的扩展
class MyClass {
companion object { } // 将被称为 "Companion"
}
fun MyClass.Companion.foo() {
println("伴随对象的扩展函数")
}
val MyClass.Companion.no: Int
get() = 10
fun main(args: Array<String>) {
println("no:${MyClass.no}")
MyClass.foo()
}
数据类,声明一个密封类,使用 data 修饰类
data class User(val name: String, val age: Int)
fun main(args: Array<String>) {
val jack = User(name = "Jack", age = 1)
// 复制数据
val olderJack = jack.copy(age = 2)
println(jack)
println(olderJack)
}
密封类,声明一个密封类,使用 sealed 修饰类
sealed class Expr
data class Const(val number: Double) : Expr()
data class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
fun eval(expr: Expr): Double = when (expr) {
is Const -> expr.number
is Sum -> eval(expr.e1) + eval(expr.e2)
NotANumber -> Double.NaN
}
泛型
class Box<T>(t: T) {
var value = t
}
val box: Box<Int> = Box<Int>(1)
// 或者
val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box。
fun <T> boxIn(value: T) = Box(value)
// 以下都是合法语句
val box4 = boxIn<Int>(1)
val box5 = boxIn(1) // 编译器会进行类型推断
// Comparable上约束
fun <T : Comparable<T>> sort(list: List<T>) {
// ……
}
// 使用 out 使得一个类型参数协变
// 定义一个支持协变的类
class Runoob<out A>(val a: A) {
fun foo(): A {
return a
}
}
fun main(args: Array<String>) {
var strCo: Runoob<String> = Runoob("a")
var anyCo: Runoob<Any> = Runoob<Any>("b")
anyCo = strCo
println(anyCo.foo()) // 输出 a
}
对象表达式
// 通过对象表达式实现一个匿名内部类的对象用于方法的参数中
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ...
}
override fun mouseEntered(e: MouseEvent) {
// ...
}
})
// 对象可以继承于某个基类,或者实现其他接口
open class A(x: Int) {
public open val y: Int = x
}
interface B {……}
val ab: A = object : A(1), B {
override val y = 15
}