Різниця між типами списку та масиву в Котліні


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>т.д. Логіка подання пам'яті та логіка операцій списків визначаються в конкретному виконанні, наприклад, індексація в 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>розглядається з Котліна як 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 немає доступних еквівалентів незмінних колекцій.


Я тут не повністю переконаний. Що в ньому змінюється 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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.