1 数组
1.1 Kotlin versus Java
| Kotlin | Java | |
|---|---|---|
| 整型 | IntArray | int[] |
| 整型装箱 | Array<Int> | Integer[] |
| 字符 | CharArray | char[] |
| 字符装箱 | Array<Char> | Character[] |
| ... | ... | ... |
| 字符串 | Array<String> | String[] |
1.2 数组的创建
- 调用形如xxxArrayOf(E1, E2, E3, ... , En)函数构建基本数据类型的数组;
- 调用形如IntArray(5) { 6 * (it + 1) }的构造函数构建包装数据类型的数组;
- 调用形如Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }的构造函数,创建自定义类型的数组;
- 注意!lambda表达式不规定传入参数时,默认有一个it,高阶函数另外讨论。
//Kotlin
fun main() {
val arr0 = intArrayOf(1, 2, 3, 4)
val arr1 = IntArray(5) { 6 * (it + 1) }
val arr2 = IntArray(3) { i -> i * 2 + 1 }
val arr3 = Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }
println(arr0.contentToString())//[1, 2, 3]
println(arr1.contentToString())//[9, 10, 11, 12, 13]
println(arr2.contentToString())//[1, 3, 5]
println(arr3.contentToString())//[No.1 person's age is 10, No.2 person's age is 20]
}
class Person(var index: Int, var age: Int) {
override fun toString(): String {
return "No.$index person's age is $age"
}
}
1.3 数组的长度
-
Java中,字符串使用length()方法,数组使用length字段,集合类使用size()方法;
-
Kotlin中,字符串使用length属性,数组使用size属性,集合类使用size属性。
//Kotlin
fun main() {
//字符串length字段
val str = "Hello Kotlin"
println(str.length)//12
//数组size字段
val arr0 = intArrayOf(1, 2, 3, 4)
val arr1 = IntArray(5) { 6 * (it + 1) }
val arr2 = IntArray(3) { i -> i * 2 + 1 }
val arr3 = Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }
println(arr0.size)//4
println(arr1.size)//5
println(arr2.size)//3
println(arr3.size)//2
//集合类size字段
val al = ArrayList<Int>();
println(al.size)//0
al.add(100)
al.add(200)
println(al.size)//2
al.remove(100)
println(al.size)//1
val hs = HashSet<Int>()
println(hs.size)//0
hs.add(100)
hs.add(200)
println(hs.size)//2
hs.remove(100)
println(hs.size)//1
}
class Person(var index: Int, var age: Int) {
override fun toString(): String {
return "No.$index person's age is $age"
}
}
1.4 数组的遍历
//kotlin
fun main() {
val arr0 = intArrayOf(1, 2, 3, 4)
val arr1 = IntArray(5) { 6 * (it + 1) }
val arr2 = IntArray(3) { i -> i * 2 + 1 }
val arr3 = Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }
//1 in关键字,类似Java的增强for循环
for (ele in arr0) {
println(ele)
}
//2 forEach()高阶函数
arr1.forEach { println(it) }
//3 利用区间获取索引
for (i in 0 until arr2.size) {
println(arr2[i])
}
//4 利用数组的区间属性获得每一个元素的索引
for (i in arr3.indices) {
println(arr3[i])
}
}
class Person(var index: Int, var age: Int) {
override fun toString(): String {
return "No.$index person's age is $age"
}
}
上面的代码演示了4中遍历数组元素的方法,分别是:
- 利用in关键字,遍历数组中的每一个元素;这种方法类似于Java的增强for循环,不同的是,Kotlin可以自动类型推导元素类型,因此Kotlin不需要写元素类型声明;
- 利用forEach()高阶函数,遍历数组中的每一个元素;
- 利用区间 0 until arr.size获得每一个元素的索引,遍历数组中的每一个元素;
- 类似于3,Kotlin意识到遍历每一个元素的场景很多,直接赋予数组类型一个区间字段arr.indices
思考,如何遍历索引为偶数(或奇数)的元素?
//Java
int[] arr = new int[]{0, 1, 2, 3, 4, 5, 6};
for (int i = 0; i < arr.length; i += 2) {
System.out.println(arr[i]);
}
//Kotlin
val arr = intArrayOf(0, 1, 2, 3, 4, 5, 6)
for (i in arr0.indices step 2) {
println(arr0[i])
}
1.5 元素是否在数组中
注意!in表达式在这里是Boolean类型。
//Kotlin
fun main() {
val arr0 = intArrayOf(1, 2, 3, 4)
val arr1 = Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }
val arr2 = arrayOf("abc", "def", "ghi")
println(1 in arr0)//true
println(Person(1,10) in arr1)//false
println("abc" in arr2)//true
println(String("abc".toCharArray()) in arr2)//true
}
class Person(var index: Int, var age: Int) {
override fun toString(): String {
return "No.$index person's age is $age"
}
}
上述代码中,我们展示了几种情况下的in表达式:
1、3很好理解,1和"abc"都是字面量,所以打印了true;
2是false是因为,in表达式中的Person(1,10)和数组中的Person(1,10)其实并非同一个对象,且该Person类没有重写equals()方法,所以是false;
4是true与3相反,因为String类型重写了equals()方法,所以比较String对象的时候,会比较String对象的内容;
如果Person类也重写equals()方法,则第二句打印将输出true。
//Kotlin
fun main() {
val arr1 = Array<Person>(2) { Person(it + 1, 10 * (it + 1)) }
println(Person(1,10) in arr1)//true
}
class Person(var index: Int, var age: Int) {
override fun toString(): String {
return "No.$index person's age is $age"
}
override fun equals(other: Any?): Boolean {
return if (other is Person) {
other.index == this.index && other.age == this.age
} else {
false
}
}
}
1.6 数组总结
2 区间
2.1 区间的创建
2.1.1 闭区间
- 整型(Int/Long/Char)创建的闭区间(IntRange/LongRange/CharRange)是离散的,可以遍历,可以用于包含判断;
- 浮点(Float/Double)创建的闭区间(FloatRange/DoubleRange)是连续的,不可以遍历,可以用于包含判断。
2.1.2 左闭右开区间
- 注意,只有整型(Int/Long/Char)才能创建左闭右开区间。
2.1.3 倒序闭区间
- 注意,只有整型(Int/Long/Char)才能创建倒序闭区间。
//Kotlin
fun main() {
//TODO:闭区间的创建
//常规的离散闭区间
val intRange = 1..10//[1,10]
val charRange = 'a'..'z'
val longRange = 1L..100L
//常规的连续闭区间
val floatRange = 1F..100F
val doubleRange = 1.0..3.0
//无符号离散区间
val uIntRange = 1U..10U
val uLongRange = 1L..4L
//TODO:左闭右开区间的创建
val range0 = 0 until 10
val range1 = 0L until 10L
val range2 = 'a' until 'z'
//val range3 = 0.0 until 10.0//无法创建连续的左闭右开区间
//val range4 = 0.0F until 10.0F//无法创建连续的左闭右开区间
//TODO:倒序闭区间的创建
val range5 = 10 downTo 0
val range6 = 10L downTo 0L
val range7 = 'z' downTo 'a'
//val range8 = 10.0 downTo 0.0//无法创建连续的倒序闭区间
//val range9 = 10.0F downTo 0.0F//无法创建连续的倒序闭区间
}
2.2 为离散区间设置步长
- 使用step关键字为离散区间设置步长,默认的步长为1。
//Kotlin
fun main() {
val range10 = 1..10 step 2
val range11 = 1L until 10L step 3
val range12 = 100 downTo 0 step 4
//val range13 = 1.0..3.0 step 2//连续的区间无法设置步长
//val range14 = 1.0F..3.0F step 2//连续的区间无法设置步长
}
2.3 打印区间
- 离散区间调用joinToString()方法,即可打印区间的内容;
- 连续的区间没有上述方法,直接调用toString()方法,将打印该区间的描述。
//Kotlin
fun main() {
val range15 = 1..10
println(range15.joinToString())//1, 2, 3, 4, 5, 6, 7, 8, 9, 10
val range16 = 100L..110L step 3
println(range16.joinToString())//100, 103, 106, 109
val range17 = 1.0F..3.0F
//println(range17.joinToString())//没有该方法
println(range17.toString())//1.0..3.0
val range18 = true..false
//println(range18.joinToString())//没有该方法
println(range18.toString())//true..false
}
2.4 判断某值是否属于区间
- 利用in/!in判断某数是否属于某区间;
- 注意!无符号数值与有符号区间不兼容,有符号数值与无符号区间也不兼容(无符号类型处于Kotlin试验阶段)。
//Kotlin
fun main() {
val range19 = 1..10
val range20 = 1U..10U
val int1 = 8
val uInt1 = 8U
println(int1 in range19)//true
//println(uInt1 in range19)//无符号数与有符号区间无法兼容
//println(int1 in range20)//有符号数与无符号区间无法兼容
println(uInt1 in range20)//true
val range21 = 1.0..3.0
val double1 = 3.1
println(double1 in range21)//false
println(double1 !in range21)//true
}