我来学Kotlin-面向对象之属性和字段
定义属性 // TODO
定义属性 // TODO
使用关键字class来定义类: class Invoice { } 类的定义由header(类名,主构造函数,参数及类型等)和header构成,主体使用花括号包裹。头和主体都不是必须的,如果没有主体花括号可以省略。 class Empty 构造函数 类有一个主构造函数以及一个或多个辅构造函数。主构造函数是header的一部分,紧跟在类名的后面。 class Person constructor(firstName: String) { } 如果主构造函数没有注解或者可见性修饰符,关键字constructor可以省略: class Person(firstName: String) { } 主构造函数不能包含任何的求值表达式,仅仅是定义参数及类型。如果要做一些初始化的工作,可以放在以init关键字开头的代码块当中: class Customer(name: String) { init { logger.info("Customer initialized with value ${name}") } } 主构造函数的参数可以在初始化代码块中使用。同样也可以在属性的定义及初始化的时候使用: class Customer(name: String) { val customerKey = name.toUpperCase() } 属性的定义及初始化可以简单的通过构造函数完成,同时可以定义属性的可变性(mutable/immutable),var是可变,val是不可变: class Person(val firstName: String, val lastName: String, var age: Int) { // ... } 如果有可见性及注释修饰符,那么constructor关键字是不可以省略的,而且要请在constructor前面: class Customer public @Inject constructor(name: String) { ... } 辅助构造函数 辅助构造函数就像Java的多构造函数类似。在Kotlin使用constructorr关键字定义,在Java中是使用与类同名的函数名定义的。 class Person { constructor(parent: Person) { parent.children.add(this) } } 如果类有辅助构造函数同时还有主构造函数,那么辅助构造函数必须要显示的调用主构造函数,直接调用,或者调用其他的辅助构造函数。调用其他的构造函数可以使用this关键字: ...
Kotlin有三种结构性的跳转表达式: return默认从最近的函数或者匿名函数返回,后面的代码不再执行 break跳出break最近的一个循环 continue忽略后面的代码,跳转到下一个步骤 所有这些表达式都可以用作更大的表达式的一部分: val s = person.name ?: return 这个表达式的类型是Nothing类型 break和continue标签 在Kotlin里所有的表达式都可以用一个标签(label)来标记。标签由一个合法的标识符跟上一个@符号缓存,例如:abc@, fooBar@都是合法的标签。要标记一个表达式,只需要把标签放在表达式前面即可: loop@ for (i in 1..10) { for (j in 1..10) { if (j > 5) break@loop println("i, j = $i, $j") } } 上面这段代码的输出如下: i, j = 1, 1 i, j = 1, 2 i, j = 1, 3 i, j = 1, 4 i, j = 1, 5 如果没有loop标签,那么break的行为是跳出里面一层的循环,输出结果还会有i, j = 2, 1等等,加了标签后直接跳出到最外层的循环。而continue是返回到标签处继续下一次的循环,下面的代码中带标签的continue和不带标签的break作用是一样的: abc@ for (i in 1..4) { for (j in 1..4) { if (j > 2) continue@abc println("i, j = $i, $j") } } for (i in 1..4) { for (j in 1..4) { if (j > 2) break println("i, j = $i, $j") } } return 关键字return跟Java的差不多,但是功能要复杂一些,个人认为没有Scala的函数式那么纯粹。return是用在函数里面来返回一个值给调用者。 ...
流程控制与Java差不多,但是更加强大,像if, when是语句也是表达式,表达式有返回值,可以赋值给一个变量。 if表达式 在Kotlin里,if是一个表达式,也就是他会返回一个值。因此没有三目运算符(? :),因为完全可以用if替代 // Traditional usage var max = a if (a < b) max = b // With else var max: Int if (a > b) { max = a } else { max = b } // As expression val max = if (a > b) a else b if分支可以是代码块,代码块的最后一个表达式的值就是if的返回值。 val max = if (a > b) { print("Choose a") a } else { print("Choose b") b } 如果if被当作表达式而不是语句使用时,这个表达式必须要有else分支。 ...
包对于模块化是非常重要的,Kotlin的包与Java的定义/语法类似,但是限制完全不同。 一个源文件的包定义应该放在代码开始处: package foo.bar fun baz() {} class Goo {} // ... 所有的内容被包含在此包的定义下面,在上面的例子中,baz()的全名是foo.bar.bax,Goo的全名是foo.bar.Goo。如果没有指定包名,那么些文件的代码属于默认没有名字的包。 默认引入 有一些包被默认引入到每一个源文件中,不需要再另外显示的引入: kotlin.* kotlin.annotation.* kotlin.collections.* kotlin.comparisons.* (从1.1开始) kotlin.io.* kotlin.ranges.* kotlin.sequences.* kotlin.text.* 根据不同的平台还会默认引入其他的包: JVM: java.lang.* kotlin.jvm.* JS: kotlin.js.* 引入 (Imports) 除了默认引入的一些包以外,每个文件应该包含自己的引入指令。 可以引入一个单独的名称,如: import foo.Bar // Bar可以直接使用,而不需要前面的前缀foo 或者一个包下面的所有内容(包,类,对象等等): import foo.* // foo下面的所有内容都可以直接访问 如果有名称冲突了,可以使用as关键字在文件范围内重命名来消除冲突: import foo.Bar // Bar可以直接访问 import bar.Bar as bBar // 使用bBar代替'bar.Bar' 关键字import不局限于引入类,还可以引入其他的定义/声明: 顶层(包级别)的函数和属性 单例对象内定义的方法和属性 枚举常量 跟Java不同的一点是,Kotlin没有import static语法,所有的定义都是通过import关键字实现 顶层定义可见性 如果声明/定义被标记为了private,那么这个声明/定义仅仅对当前文件可见,其他包不能引用。
在Kotlin,一切皆对象,我们可以在任何变量上调用成员函数和属性。有些类型是内置的,因为它们的实现是经过优化的,但是对于用户来说,它们看起来就像普通的类。本节描述这些类型中的大多数: numbers, characters, booleans and arrays. 数字类型 Kotlin以一种接近Java的方式处理数字,但不完全一样。例如,对于数字没有隐式转换,而在某些情况下,字面量略有不同。Kotlin提供如下内置的数字类型(与Java接近): Type Bit width Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8 注意:在Kotlin中字符不是数字 字面量 整数字面量如下: 十进制:123 Long长整形使用L标识:123L 十六进制:0x0F 二进制:0b00001011 注意:不支持八进制字面量 Kotlin支持常见的浮点数字: Double双精度是默认的浮点数字:123.5, 123.5e10 单精度使用f或者F标识:123.5f 使用下划线(1.1或更高版本) 比较长的数字使用下划线可以更易于阅读,这和Swift的使用方法一样 val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L val socialSecurityNumber = 999_99_9999L val hexBytes = 0xFF_EC_DE_5E val bytes = 0b11010010_01101001_10010100_10010010 Representation 在JVM平台,数字被物理地存储为JVM原始类型,除非我们需要一个可空的数字引用(例如Int?)或者泛型。在后一种情况下数字会被装箱(boxed)。 注意:装箱后的数字不一定会保持引用 val a: Int = 10000 print(a === a) // Prints 'true' val boxedA: Int? = a val anotherBoxedA: Int? = a print(boxedA === anotherBoxedA) // !!!Prints 'false'!!! 但是会保持值的相等(使用两个等号==)。三个等号(===)会判断是否是同一个对象,就是上面说的引用,内存地址相等。 ...
Kotlin官方提供了一份代码规范,主要介绍了命名,冒号,匿名函数,类定义,方法与属性以及Unit,比较简短。 下面是Kotlin官方提倡的一份代码规范 命名 如果有不确定的可以参考Java代码规范,例如: 使用驼峰法来命名,避免使用下划线 类型/类使用大写字母开头 方法/属性/函数以小宝字母开头 使用4个空格缩进 public方法应该写上注释,以便生成文档的时候会显示注释内容 冒号 如果冒号出现在类型与类型之间,前后都应该有一个空格。而如果出现在变量名与其类型之间,前面不要空格,后面应该有一个空格: interface Foo<out T : Any> : Bar { fun foo(a: Int): T } 匿名函数/Lambdas 匿名函数在花括号内部两边应留一个空格,与前面调用的函数名之间留一个空格,剪头两边也需要有空格: list.filter { it > 10 }.map { element -> element * 2 } 匿名函数应该尽量简短,避免嵌套。推荐使用it代替自定义的参数名。在嵌套匿名函数里,最好显示的自定义参数名称。 类定义格式 如果类包含较少的参数,应该写在一行: class Person(id: Int, name: String) 如果比较长的话,构造函数的参数一个写一行,前面使用4个空格缩进,右圆括号另起一行。如果使用了继承,那么父类的构造函数或者接口应该写在括号后面: class Person( id: Int, name: String, surname: String ) : Human(id, name) { // ... } 如果继承了父类以及多个接口,父类与括号写在一行,每个接口单独写一行: class Person( id: Int, name: String, surname: String ) : Human(id, name), KotlinMaker { // ... } Unit 函数返回Unit时,函数的返回值类型可以省略: ...
数据类 data class Customer(val name: String, val email: String) Customer提供了以下方法: getters,如果成员变量使用var定义那么还默认提供setters equals() hashCode() toString() copy() component1(), component2() … 这跟Scala的case class基本上差不多,一般在做数据交互/传输时用 函数默认值 fun foo(a: Int = 0, b: String = "") { ... } 列表过滤 val positives = list.filter { x -> x > 0 } 或者更短一点 val positives = list.filter { it > 0 } 默认使用it来接收单个的参数 字符串插值 println("Name $name") 对象检查 when (x) { is Foo -> ... is Bar -> ... else -> ... } 非常精简,再也不要写Java那个烦人的instanceof 遍历映射/列表 for ((k, v) in map) { println("$k -> $v") } k, v分别是map的key和value,是list的index和value ...
零、咱们先来看看Kotlin是啥语言。 JetBrains在2016年2月15日Kotlin 1.0发布,这意味着Kotlin经过几年的发展已经稳定而且可以在生产环境使用。再来看一下其他人: 如何评价 Kotlin 语言 Android开发时你遇到过什么相见恨晚的工具或网站 Kotlin, the Swift of Android Using Project Kotlin for Android 使用Kotlin进行Android开发 在网搜索一下就会发现已经有很多人在研究Kotlin并且使用其来开发Android,Android Studio原生就内置了Kotlin的工具和插件,可以方便的使用Kotlin开发Android。个人认为Kotlin没有Java那么多的历史包袱,而且写起来也没有Java那么的繁琐,但是又可以跟Java无缝结合,可以完全使用现在的各种库;相比Scala又简单不少。应该在JVM平台上可以发展得不错。我来学系列记录我自己学习的过程,同时希望可以能跟猿猴们一起探讨开发。下面的内容基本上是照着官方的文档来写,一来自己学习,二来跟大家一起讨论。 一、快速浏览语法 包定义 这个跟Java没有多少区别,在文件的最上面定义包的名字。如果需要引用其他包的内容,紧接着包定义的下面引入: package my.demo import java.util.* // ... 在Kotlin里面包的名字不一定要跟文件路径一致,一个源代码文件可以定义任意的包名。 定义函数 跟Java不同的是,在Kotlin里面可以定义单独的函数,而Java的函数必须属于某个类。下面是一个求和函数,把两个Int类型的变量相加,返回相加后的结果: fun sum(a: Int, b: Int): Int { return a + b } 还可以使用表达式的方式和类型推导来把上面的代码写得更加简洁: fun sum(a: Int, b: Int) = a + b 函数可以返回一个代表无值的值Unit,这有点像Java里面的void,但是跟void的意思大不相同。Unit类型表示一个值,但是这个值里面什么都没有: fun printSum(a: Int, b: Int): Unit { println("sum of $a and $b is ${a + b}") } 如果函数没有返回值,返回值缺省就是Unit ...