在上篇笔记中,我们对 Kotlin 的基本类型、关键字、类与对象,以及与 Java 之间互调的内容有了一些认识,这篇笔记来看看 Kotlin 中几种特殊的类,以及集合相关的常用操作。
1. Kotlin 数据类
Kotlin 语言中有个特殊的类叫 数据类,这个类型是 Kotlin 专门用来表示一个 Java Bean 的,为啥这么说?因为它帮我们自动生成了一个数据类应该有的方法。比如:getter/setter 方法、toString()、hashCode()、equals()、copy() 方法。举个栗子:
// code 1 data class Book(val id: Int, val name: String) { }
Kotlin 代码就这么点,然后再看看为我们生成的 Java 代码:(如何查看生成的 Java 代码?找到 AndroidStudio 的 Tools 选项,依次选 Kotlin、show Kotlin ByteCode,然后在新出现的代码窗口点击 Decompile 就可以看到生成的 Java 代码了)
// code 2 public final class Book { private final int id; @NotNull private final String name; public final int getId() { return this.id; } @NotNull public final String getName() { return this.name; } public Book(int id, @NotNull String name) { Intrinsics.checkNotNullParameter(name, "name"); super(); this.id = id; this.name = name; } public final int component1() { return this.id; } @NotNull public final String component2() { return this.name; } @NotNull public final Book copy(int id, @NotNull String name) { Intrinsics.checkNotNullParameter(name, "name"); return new Book(id, name); } // $FF: synthetic method public static Book copy$default(Book var0, int var1, String var2, int var3, Object var4) { if ((var3 & 1) != 0) { var1 = var0.id; } if ((var3 & 2) != 0) { var2 = var0.name; } return var0.copy(var1, var2); } @NotNull public String toString() { return "Book(id=" + this.id + ", name=" + this.name + ")"; } public int hashCode() { int var10000 = this.id * 31; String var10001 = this.name; return var10000 + (var10001 != null ? var10001.hashCode() : 0); } public boolean equals(@Nullable Object var1) { if (this != var1) { if (var1 instanceof Book) { Book var2 = (Book)var1; if (this.id == var2.id && Intrinsics.areEqual(this.name, var2.name)) { return true; } } return false; } else { return true; } } }
想不到吧?一行 Kotlin 竟然帮我们干了这么多事!这也说明用 Kotlin 确实能减少代码量,提升 Coding 效率。再看看 Kotlin 数据类的特点。
首先,data class 是一个 final 类,说明 data class 是无法被继承的,哪怕在它前面加 open 关键字也不行。细心的同学可能发现了:这个 Book 并没有 setter 方法呀?没错,那是因为之前在写 Kotlin 代码时,把 id 和 name 两个参数设置为 val 不可变变量了,如果改成 var 再次生成一下,你就会发现有 setter 方法了。
然后,其他的 hashCode、toString、equals、copy 方法都是常规的一些操作,当然,也可以在 data class 里面重写这些方法,达到自己想要的效果。
再看一眼,发现还有两个比较陌生的方法:component1() 和 component2(),和 getter 方法一样啊,为啥?其实这两个方法是 data class 用来解构的,方便用户直接拿到某个对象中的属性值,如下:
// code 3 val book = Book(1, "鲁迅文集") book.id = 23 // setter 方法 val(bookId, bookName) = book // 对 book 直接解构 print("bookName = $bookName") // 输出:“bookName = 鲁迅文集”
如果还有第三个属性的话一样的,就会给你生成 component3(),以此类推。这两个 component 是 data class 自动生成的,如果普通的 class 也想这样解构,也可以,需要使用 operator 关键字,对类中的属性做一个关联:
// code 4 class Car(var brand: String, var price: Double) { // 普通类 解构 operator fun component1(): String { return this.brand } operator fun component2(): Double { return this.price } }
operator 关键字可以用来重载操作符或者实现一个约定。这里就是实现了一个约定。这样写之后就可以像 data class 一样进行解构了。Kotlin 的这种解构方式用的比较多的地方是在 Map 数据结构中,它不需要像 Java 一样先拿到 Entry 对象,然后才能拿到 key 值和 value 值,直接用这种解构即可。
// code 5 val person = mapOf<String, String>("name" to "Jack", "age" to "23") for ((key, value) in person) { println("key: $key ==== value: $value") } // (是不是比 Java 方便多了?)
2. Kotlin 枚举类(密闭类)
Kotlin 中也有枚举类,使用方法与 Java 的枚举类一样,此外,Kotlin 还有一个更加强大的枚举类,称为密闭类,用 sealed 关键字修饰。密闭类可以有自己的子类,而且可以扩展它的子类,例如给子类设置一些参数等,要知道,枚举类是不具有这种特点的:
// code 6 // Kotlin 密闭类(高级枚举类) sealed class Language { object English: Language() object Japanese: Language() class Chinese(var isDialect: Boolean): Language() // 是否方言 }
3. Kotlin 循环写法
这个就没啥可说了,直接上代码!
// code 7 for (i in 1..10) { // 注意 x..y 表示的是 x<= i <= y,都是闭区间,且 x <= y,否则 i 为空 print("$i ") // 输出 1 2 3 4 5 6 7 8 9 10 } for (i in 1 until 10) { // 区间为 前闭后开 print("$i ") // 输出 1 2 3 4 5 6 7 8 9 } for (i in 10 downTo 1) { // 递减循环 print("$i ") // 输出 10 9 8 7 6 5 4 3 2 1 } for (i in 1..10 step 2) { // step 为步进长 print("$i ") // 输出 1 3 5 7 9 } repeat(10) { // 高阶函数,大括号里表示的是 Lambda 表达式,传进的参数为循环执行这个表达式多少次,it 表示的是目前执行的是第几次,从 0 开始 print(it) // 输出 0123456789 } // 平时用的比较多的还是取集合中的元素 val list = listOf("I","am","Chinese") for (str in list) { print("$str ") } for ((index, str) in list.withIndex()){ print("第${index}元素是$str") }