不可变Set同样是继承了Collection。MutableSet接口继承于Set, MutableCollection,同时对Set进行扩展,添加了对元素添加和删除等操作。

    Set的类图结构如下:

    万物生于无。我们先来看下Kotlin中的空集:

    空集继承了Serializable,表明是可被序列化的。它的size是0, isEmpty()返回true,hashCode()也是0。

    下面是创建一个空集的代码示例:

    1. >>> val emptySet = emptySet<Int>()
    2. >>> emptySet
    3. []
    4. >>> emptySet.size
    5. 0
    6. >>> emptySet.isEmpty()
    7. true
    8. >>> emptySet.hashCode()
    9. 0

    setOf

    首先,Set中的元素是不可重复的(任意两个元素 x, y 都不相等)。这里的元素 x, y 不相等的意思是:

    1. x.hashCode() != y.hashCode()
    2. !x.equals(y)

    上面两个表达式值都为true 。

    代码示例

    1. >>> val list = listOf(1,1,2,3,3)
    2. >>> list
    3. [1, 1, 2, 3, 3]
    4. >>> val set = setOf(1,1,2,3,3)
    5. >>> set
    6. [1, 2, 3]

    创建多个元素的Set使用的函数是

    1. setOf(vararg elements: T): Set<T> = if (elements.size > 0) elements.toSet() else emptySet()

    这个toSet()函数是Array类的扩展函数,定义如下

    我们可以看出,setOf函数背后实际上用的是LinkedHashSet构造函数。关于创建Set的初始容量的算法是:

    1. @PublishedApi
    2. internal fun mapCapacity(expectedSize: Int): Int {
    3. if (expectedSize < 3) {
    4. return expectedSize + 1
    5. }
    6. return expectedSize + expectedSize / 3
    7. }
    8. return Int.MAX_VALUE // 2147483647, any large value
    9. }

    也就是说,当元素个数n小于3,初始容量为n+1; 当元素个数n小于2147483647 / 2 + 1 , 初始容量为 ; 否则,初始容量为2147483647

    如果我们想对一个List去重,可以直接使用下面的方式

    1. >>> list.toSet()
    2. [1, 2, 3]

    上文我们使用emptySet<Int>()来创建空集,我们也可以使用setOf()来创建空集:

    1. >>> val s = setOf<Int>()
    2. >>> s
    3. []

    创建1个元素的Set:

    1. >>> val s = setOf<Int>(1)
    2. >>> s
    3. [1]

    这个函数调用的是setOf(element: T): Set<T> = java.util.Collections.singleton(element), 也是Java的Collections类里的方法。

    mutableSetOf(): MutableSet<T>

    创建一个可变Set。

    这个LinkedHashSet()构造函数背后实际上是java.util.LinkedHashSet<E>, 这就是Kotlin中的类型别名。

    包kotlin.collections下面的TypeAliases.kt类中,有一些类型别名的定义如下:

    1. @file:kotlin.jvm.JvmVersion
    2. package kotlin.collections
    3. @SinceKotlin("1.1") public typealias RandomAccess = java.util.RandomAccess
    4. @SinceKotlin("1.1") public typealias ArrayList<E> = java.util.ArrayList<E>
    5. @SinceKotlin("1.1") public typealias LinkedHashMap<K, V> = java.util.LinkedHashMap<K, V>
    6. @SinceKotlin("1.1") public typealias HashMap<K, V> = java.util.HashMap<K, V>
    7. @SinceKotlin("1.1") public typealias LinkedHashSet<E> = java.util.LinkedHashSet<E>
    8. @SinceKotlin("1.1") public typealias HashSet<E> = java.util.HashSet<E>
    9. // also @SinceKotlin("1.1")
    10. internal typealias SortedSet<E> = java.util.SortedSet<E>
    11. internal typealias TreeSet<E> = java.util.TreeSet<E>

    从这里,我们可以看出,Kotlin中的LinkedHashSet , HashSet, , TreeSet 就是直接使用的Java中的对应的集合类。

    对应的创建的方法是

    1. linkedSetOf
    2. mutableSetOf
    3. sortedSetOf

    代码示例如下:

    1. >>> val hs = hashSetOf(1,3,2,7)
    2. >>> hs
    3. [1, 2, 3, 7]
    4. >>> hs::class
    5. class java.util.HashSet
    6. >>> val ls = linkedSetOf(1,3,2,7)
    7. >>> ls
    8. [1, 3, 2, 7]
    9. >>> ls::class
    10. class java.util.LinkedHashSet
    11. >>> val ms = mutableSetOf(1,3,2,7)
    12. >>> ms
    13. [1, 3, 2, 7]
    14. >>> ms::class
    15. class java.util.LinkedHashSet
    16. >>> val ss = sortedSetOf(1,3,2,7)
    17. >>> ss
    18. [1, 2, 3, 7]
    19. >>> ss::class
    20. class java.util.TreeSet

    我们知道在Java中,Set接口有两个主要的实现类HashSet和TreeSet:

    HashSet : 该类按照哈希算法来存取集合中的对象,存取速度较快。 TreeSet : 该类实现了SortedSet接口,能够对集合中的对象进行排序。 LinkedHashSet:具有HashSet的查询速度,且内部使用链表维护元素的顺序,在对Set元素进行频繁插入、删除的场景中使用。

    Kotlin并没有单独去实现一套HashSet、TreeSet和LinkedHashSet。如果我们在实际开发过程中,需要用到这些Set, 就可以直接用上面的方法。

    Kotlin中针对Set做了一些加减运算的扩展函数, 例如:

    1. operator fun <T> Set<T>.plus(element: T)
    2. plusElement(element: T)
    3. plus(elements: Iterable<T>)
    4. operator fun <T> Set<T>.minus(element: T)
    5. minusElement(element: T)
    6. minus(elements: Iterable<T>)