Kotlin为数组增加了一个Array 类,为元素是基本类型的数组增加了 XxxArray 类(其中 Xxx 可以是 Byte、Short、 Int 等基本类型),因此开发者完全可用面向对象的语法来使用 Kotlin 的数组,包括创建数组对象、调用数组对象的属性和方法等 。
Kotlin 自己提供了一套集合体系, Kotlin 的集合体系抛弃了 Java集合体系中的 Queue集合, 但增加了可变集合和不可变集合的概念 。 Kotlin 的集合体系由三种集合组成,如图所示 :
与 Java 集合类似的是,Kotlin的ist代表着有序,集合元素可重复的集合,Set代表着无序、集合元素不可重复的集合; Map 则采用 key-value 对的形式存储数据,每项数据都由 key-value 对组成 。
数组
Kotlin 的数组使用 Array<T>类代表,由此可见,Kotlin数组就是一个 Array类的实例,因此 Kotlin数组当然也算引用类型了。
创建数组
Kotlin 创建数组其实就是创建 Array<T>类的实例, Kotlin 既可允许通过 Array<T>类的构造器来创建实例,也可通过 arrayOf()等工具函数来创建实例。
Kotlin 创建数组大致有如下两种方式。
- 使用 arrayOf()、 arrayOfNulls()、 emptyArray()工具函数。
- 使用 Array(size: Int, init: (Int) -> T)构造器。
fun main(args: Array<String>) {
//创建包含指定元素的数组(相当于 Java 数组的静态初始化〉
var arr1 = arrayOf("c", "c#", "c++")
var intArr1 = arrayOf(2, 3, 4, 6, 7, 8)
//创建指定长度、元素为 null 的数组(相当于 Java 数组的动态初始化)
var arr2 = arrayOfNulls<Double>(5)
var intArr2 = arrayOfNulls<Int>(6)
//创建长度为 0 的空数组
var arr3 = emptyArray<String>()
var intArr3 = emptyArray<Int>()
//创建指定长度、使用 Lambda 表达式初始化数组元素的数组
var arr4 = Array(5, { (it * 2 + 97).toChar() })
var strArr4 = Array(6, { "css" })
for (item in strArr4) {
println(item)
}
}
- 使用 arrayOf()函数:这种方式无须显式指定数组的长度,但需要依次列出每个数组元素。因此,这种方式其实就相当于 Java数组的静态初始化。使用这种方式创建数组时, 由于程序己经给出了每个数组元素,因此 Kotlin 可以推断出数组元素的类型。所以, 不需要在 arrayOf()函数上使用泛型来指定数组元素的类型。
- 使用 arrayOfNulls()函数:这种方式需要显式指定数组的长度,数组元素全部被初始化为null,可见这种方式就是 Java数组的动态初始化。使用这种方式创建数组时,由于 Kotlin 无法推断出数组元素的类型,所以需要在 arrayOfNulls()函数上使用泛型来指定数组元素的类型。
- 使用 emptyArray()函数: 这种方式会创建一个长度为 0 的空数组。由于没有指定数组元素,因此需要使用泛型来指定数组元素的类型。
- 使用 Array(size: Int, init: (Int) -> T)构造器: 这种方式需要显式指定数组的长度,并可通过 Lambda表达式来动态计算各数组元素的值。这种方式是原来 Java所不具备的。
此外,由于 Array<T>类要求它的元素必须是引用类型,因此,如果程序将基本类型的值存入 Array<T>中, Kotlin 会将这些基本类型的值自动装箱成包装类的实例,然后才将这些实例添加到 Array<T>数组中。为此, Kotlin 专门提供了 ByteArray、ShortArray、IntArray、LongArray、 CharArray、FloatArray、DoubleArray、BooleanArray,分别用于映射 Java的 byte[]、short[]、int[]、 long[]、 char[]、 float[]、 double[]、 boolean[]这 8 种基本类型的数组。
创建 XxxArray 对象的方式与前面介绍的方式大致相同 。例如:
fun main(args: Array<String>) {
//创建包含指定元素的数组(相当于 Java 数组的静态初始化)
var intArr1 = intArrayOf(1, 2, 3)
var doubleArr1 = doubleArrayOf(1.1, 2.3, 4.5)
//创建指定长度、使用 Lambda表达式初始化数组元素的数组
var intArr2 = IntArray(5, { it * it })
var charArray = CharArray(4, { (it * 2 + 97).toChar() })
//输出[0, 1, 4, 9, 16]
println(Arrays.toString(intArr2))
}
从上面代码可以看出,对于 XxxArray数组,同样可采用列出数组元素(静态初始化)的方式来创建数组,但不支持使用将元素初始化为 null 的方式来创建数组,这是因为基本类型的元素不允许为 null。
使用数组
数组的常用方法就是访问数组元素,包括对数组元素进行赋值和取出数组元素的值。访问数组元素都是通过在数组引用变量后紧跟一个方括号([])实现的,方括号里是数组元素的索引值,正如前面所介绍的, Kotiin 的方括号运算符其实是 get(index)和 set(index, value)方法, 因此当程序使用[i]获取数组元素的值时,实际上就是调用 get(index)方法;当使用 [index]对数组元素赋值时,实际上就是调用 set(index,value)方法。
fun main(args: Array<String>) {
//创建包含指定元素的数组(相当于 Java 数组的静态初始化)
var intArr1 = intArrayOf(1, 2, 3)
println(intArr1[1])
println(intArr1.get(1))
intArr1.set(0,10)
intArr1.set(1,20)
println(Arrays.toString(intArr1))
}
fun main(args: Array<String>) {
//创建包含指定元素的数组(相当于 Java 数组的静态初始化)
var intArr1 = intArrayOf(1, 2, 3)
println(intArr1[1])
println(intArr1.get(1))
intArr1.set(0, 10)
intArr1.set(1, 20)
println(Arrays.toString(intArr1))
//通过得到数组的size,遍历数组
for (i in 0 until intArr1.size) {
println(intArr1[i])
}
//for-in循环遍历数组
for (item in intArr1) {
println(item)
}
//使用数组索引遍历
for (i in intArr1.indices){
println(intArr1[i])
}
//判断是否在索引的区间内
println(1 in intArr1.indices)
}
数组的常用方法
fun main(args: Array<String>) {
//定义一个数组
var intArr1 = arrayOf(1, 4, 5, 6)
//判断所有数的平方是不是都大于20
println(intArr1.all({ it * it > 20 }))
//判断是否有一元素的平方大于 20
println(intArr1.any({ it * it > 20 }))
//根据数组元素来计算< K, V>对,返回所有< K, V>对组成的 Map 集合
// 下面的算法规则是: K 是数组元素+ 10, v 是数组元素的平方
println(intArr1.associate({ it + 10 to it * it }))
//创建一个可变 Map 集合,用于追加根据数组计算出来的 key-value 对
var map = mutableMapOf(1 to 100, 2 to 120, -1 to 130)
//将计算出来的 key (元素的平方)、 value (元素)对添加到 map 集合中
intArr1.associateByTo(map, { it * it })
println(map)
//计算数组所有元素的总和
println(intArr1.fold(0, { acc, e -> acc + e }))
//定义一个 a 数组
var a = arrayOf(3, 4, 5, 6)
//定义一个 a2 数组
var a2 = arrayOf(3, 4, 5, 6)
// a 数组和 a2 数组的长度相等,每个元素依次相等 , 将输出 true
println("a 数组和 a2 数组是否相等:${a.contentEquals(a2)}")
//通过复制 a 数组,生成一个新的 b 数组
var b = a.copyOf(6)
println("a 数组和 b 数组是否相等:${a.contentEquals(b)}")
//输出b数组
println(Arrays.toString(b))
println(b.contentToString())
//计算两个集合的并集
println((b + a).contentToString())
}
多维数组
所谓的多维数组其实都是一维数组,只要让数组的元素又是数组,那么该数组就变成了多维数组 。
fun main(args: Array<String>) {
//定义二维数组
var arr1 = arrayOfNulls<Array<Int>>(4)
//同时初始化二维数组的两个维数
var b = Array<IntArray>(3 , {IntArray(4 , {0}) })
for (i in arr1.indices){
println(arr1[i])
}
//初始化 arr1 数组的第一个元素
arr1[0] = arrayOf(1,2,3)
//访问 arr1数组的第一个元素所指数组的第二个元素
arr1[0]?.set(1,6)
//arr1数组的第一个元素是一个一维数组, 遍历这个一维数组
for (i in arr1[0]!!.indices){
println(arr1[0]!![i])
}
}
Kotlin 集合概述
Kotlin 的集合类同样由两个接口派生: Collection 和 Map。 Collection 和 Map是Java 集合框架的根接口,这两个接口又包含了一些子接口或实现类 。Kotlin 集合与 Java 集合不同, Java 集合都是可变集合,开发者可以向集合中添加、删除、修改元素,但 Kotlin 的集合被分成两大类 : 可变集合和不可变集合。只有可变集合才能添加、删除、修改元素,不可变集合只能读取元素。
纵观 Kotiin 集合体系,不难发现 Kotlin 只提供了 HashSet、 HashMap、 LinkedHashSet、LinkedHashMap、 ArrayList这5个集合实现类,而且它们都是可变集合。那么说好的不可变集合呢? Kotlin 的不可变集合类并没有暴露出来,我们只能通过函数来创建不可变集合。
Set集合
实际上 Kotlin并没有真正为JVM平台实现任何 Set集合类(只是通过别名借用了Java集合框架的类),因此不推荐通过构造器创建 Set 集合,而是推荐使用 Kotlin 提供的工具函数来创建Set集合。
Kotlin提供了如下函数来创建 Set集合。
- setOf(): 该函数返回不可变的 Set 集合。该函数可接受 0 个或多个参数,这些参数将作为集合的元素。保证元素的顺序。
- mutableSetOf(): 该函数返回可变的 MutableSet 集合。该函数可接受 0 个或多个参数, 这些参数将作为集合的元素。
- hashSetOf(): 该函数返回可变的 HashSet 集合。该函数可接受0个或多个参数,这些参数将作为集合的元素。
- linkedSetOf():该函数返回可变的 LinkedHashSet集合。该函数可接受 0个或多个参数,这些参数将作为集合的元素。
- sortedSetOf():该函数返回可变的 TreeSet集合 。该函数可接受 0个或多个参数,这些参数将作为集合的元素 。
如下程序示范了使用工具函数创建 Set集合。
fun main(args: Array<String>) {
//创建不可变集合,返回值是Set
var set1: Set<String> = setOf<String>("java", "c", "c#", "c++")
//保证元素的顺序
println(set1)
//创建可变集合,返回值是 MutableSet
var set2 = mutableSetOf<String>("java", "c", "c#", "c++")
println(set2) //集合元素按添加顺序排列
println("setOf 的返问对象的实际类型:${set1.javaClass} ")
println("mutableSetOf 的返回对象的实际类型 :${set2.javaClass}")
////创建 HashSet 集合
var set3 = hashSetOf<String>("java", "c", "c#", "c++")
println(set3) //不保证元素的顺序
//创建 LinkedHashSet 集合
var set4 = linkedSetOf<String>("java", "c", "c#", "c++")
println(set4) //集合元素按添加顺序排列
//创始 TreeSet 集合
var set5 = sortedSetOf("java", "c", "c#", "c++")
println(set5) //集合元索由小到大排列
}
注意:Set不是无序集合,实际上,Set 只是一个接口,而该接口下常用的 3 个实现类,HashSet、 LinkedHashSet 和 TreeSet 中有两个是有序的。
使用set的方法
fun main(args: Array<String>) {
//创建不可变集合,返回值是Set
var set1: Set<String> = setOf<String>("java", "c", "c#", "c++", "kotlin")
//判断是否所有元素的长度都大于 4
println(set1.all({ it.length > 4 }))
//判断是否任一元素的长度都大于 4
println(set1.any({ it.length > 4 }))
//以 Lambda 表达式的值为 key,集合元素为 value,组成 Map 集合
val map = set1.associateBy({ "我想学" + it })
//{我想学java=java, 我想学c=c, 我想学c#=c#, 我想学c++=c++, 我想学kotlin=kotlin}
println(map)
//由于有 contains ()方法,所以可用 in、! in 运算符
println("java" in set1)
//返回删除 Set 集合前里两个元素后的集合
val dropList = set1.drop(2)
println(dropList)
//对 Set 集合元素进行过滤:要求集合元素包含 li
val filteredList = set1.filter { "li" in it }
println(filteredList)
//查找 Set 集合中包含 li的元素,如果找到就返回该元素,否则返回 null
val foundStr1 = set1.find { "li" in it }
println(foundStr1)
//将 Set 集合中的所有字符串拼接在一起
val foldedList = set1.fold("", { acc, e -> acc + e })
//javacc#c++kotlin
println(foldedList)
//查找某个元素的出现位置
println(set1.indexOf("java"))
//将每个集合元素映射成新值,返回所有新值组成的 Set 集合
val mappedList = set1.map { "不想学" + it }
//[不想学java, 不想学c, 不想学c#, 不想学c++, 不想学kotlin]
println(mappedList)
//获取最大值
println (set1.max())
//反转集合顺序
val reversedList = set1.reversed()
println(reversedList)
var bSet = setOf("android",".net","php","kotlin")
//计算两个集合的交集
println(set1 intersect bSet)
//计算两个集合的并集
println(set1 union bSet)
//集合相加,相当于并集
println(set1 + bSet)
//集合相减,减去它们公共的元素
println(set1 - bSet)
}
遍历Set
fun main(args: Array<String>) {
//创建不可变集合,返回值是Set
var set1: Set<String> = setOf<String>("java", "c", "c#", "c++", "kotlin")
//for-in遍历
for (item in set1){
println(item)
}
//调用 forEach 方法来遍历 Set 集合
set1.forEach { println(it) }
//由于 setOf()方法返回的 Set集合是有序的,因此可以通过索引来遍历 Set集合
for (i in set1.indices){
println(set1.elementAt(i))
}
}
可变的Set
除使用 setOf()函数返回的集合是不可变集合之外,使用 mutableSetOf()、 hashSetOf()、 linkedSetOf()、 sortedSetOf()函数返回的集合都是可变的,其中后面三个函数返回的集合类型都是明确的,依次是 HashSet、 LinkedHashSet、 TreeSet。
- 添加元素
fun main(args: Array<String>) {
//创建可变集合,返回值是MutableSet
var set1: MutableSet<String> = mutableSetOf("java", "c", "c#", "c++", "kotlin")
set1.add("111")
set1.addAll(setOf("22","333"))
}
- 删除元素
fun main(args: Array<String>) {
//创建可变集合,返回值是MutableSet
var set1: MutableSet<String> = mutableSetOf("java", "c", "c#", "c++", "kotlin")
set1.remove("c")
set1.removeAll(setOf("java","kotlin"))
println(set1)
//只保留 Set集合中与 elements 集合共有的元素
set1.retainAll(setOf("c#","oc"))
println(set1)
//清空集合
set1.clear()
}