Разница между типами List и Array в Котлине

192

В чем разница между Listи Arrayтипами?
Кажется, можно выполнять с ними одинаковые операции (циклы, выражение фильтра и т. Д.), Есть ли разница в поведении или использовании?

val names1 = listOf("Joe","Ben","Thomas")
val names2 = arrayOf("Joe","Ben","Thomas")

for (name in names1)
    println(name)
for (name in names2)
    println(name)
Даниэль Хари
источник

Ответы:

281

Массивы и списки (представленные List<T>и их подтип MutableList<T>) имеют много различий, вот наиболее значимые из них:

  • Array<T>это класс с известной реализацией: это последовательная область памяти фиксированного размера, хранящая элементы (а в JVM она представлена массивом Java ).

    List<T>и MutableList<T>являются интерфейсами, которые имеют разные реализации: ArrayList<T>и LinkedList<T>т. д. Представление в памяти и логика операций списков определены в конкретной реализации, например, индексирование в a LinkedList<T>проходит по ссылкам и занимает O (n) времени, тогда как ArrayList<T>его элементы хранятся в динамически распределенном массиве.

    val list1: List<Int> = LinkedList<Int>()
    val list2: List<Int> = ArrayList<Int>()
  • Array<T>является изменяемым (его можно изменить с помощью любой ссылки на него), но List<T>не имеет модифицирующих методов (это либо представление только для чтения,MutableList<T> либо реализация неизменяемого списка ).

    val a = arrayOf(1, 2, 3)
    a[0] = a[1] // OK
    
    val l = listOf(1, 2, 3)
    l[0] = l[1] // doesn't compile
    
    val m = mutableListOf(1, 2, 3)
    m[0] = m[1] // OK
  • Массивы имеют фиксированный размер и не могут расширять или уменьшать сохраняющуюся идентичность (вам необходимо скопировать массив, чтобы изменить его размер). Что касается списков, MutableList<T>имеет addи removeфункции, так что он может увеличивать и уменьшать свои размеры.

    val a = arrayOf(1, 2, 3)
    println(a.size) // will always be 3 for this array
    
    val l = mutableListOf(1, 2, 3)
    l.add(4)
    println(l.size) // 4
  • Array<T>является инвариантом наT ( Array<Int>не Array<Number>), то же самое для MutableList<T>, но List<T>ковариантен ( List<Int>есть List<Number>).

    val a: Array<Number> = Array<Int>(0) { 0 } // won't compile
    val l: List<Number> = listOf(1, 2, 3) // OK
  • Массивы оптимизированы для примитивов: есть отдельные IntArray, DoubleArray, и CharArrayт.д. , которые отображаются на Java примитивные массивы ( int[], double[], char[]), а не в штучной упаковке из них ( Array<Int>отображается в Java Integer[]). Как правило, списки не имеют реализаций, оптимизированных для примитивов, хотя некоторые библиотеки (за пределами JDK) предоставляют списки, оптимизированные для примитивов.

  • List<T>и MutableList<T>являются отображенными типами и имеют особое поведение в совместимости с Java (Java List<T>рассматривается Kotlin как либо, List<T>либо MutableList<T>). Массивы также отображаются, но у них есть другие правила взаимодействия Java.

  • Определенные типы массивов используются в аннотациях (примитивные массивы Array<String>и массивы с enum classзаписями), и существует специальный синтаксис литерала массива для аннотаций . Списки и другие коллекции не могут быть использованы в аннотациях.

  • Что касается использования, хорошей практикой является предпочтение использования списков, а не массивов, везде, за исключением критически важных для вашего кода частей, причина которых та же, что и для Java .

горячая клавиша
источник
26

Основное отличие от использования заключается в том, что массивы имеют фиксированный размер, в то время как (Mutable)Listмогут динамически регулировать их размер. Более того Array, изменчив, а Listнет.

Кроме того, kotlin.collections.Listинтерфейс реализован среди других java.util.ArrayList. Он также расширен kotlin.collections.MutableListдля использования, когда необходимы коллекции, которые позволяют модифицировать элементы.

На уровне jvm Arrayпредставлен массивами . Listс другой стороны, представлен как, java.util.Listпоскольку в Java нет неизменных эквивалентов коллекций.

miensol
источник
Я не полностью убежден здесь. Что изменчиво в Array? Только это элементы - то же самое в List. Размер Listтакже фиксирован.
AndroidEx
1
@AndroidEx следующее будет компилироваться, val intArray = arrayOf(1,2,3); intArray[0] = 2а это не будет val intList = listOf(1,2,3); intList[0] = 2. ListДействительно имеет фиксированный размер , но MutableListкоторый распространяется не значит , что это возможно , что val a:List<Int>сообщит разные sizeпри последующих вызовах.
miensol
Рекомендуется ли использовать Listили ArrayList?
Игорь Ганапольский
2
@IgorGanapolsky Если вас не волнует конкретное использование реализации List(вероятно, в 99% случаев 🙂). Если вы действительно заботятся об использовании реализации ArrayListили LinkedListили какой - либо другой реализации конкретной.
Miensol