Różnica między typami List a Array w Kotlin

192

Jaka jest różnica między Listi Arraytypy?
Wydaje się, że można z nimi wykonywać te same operacje (pętle, wyrażenie filtru itp.), Czy jest jakaś różnica w zachowaniu lub użyciu?

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

for (name in names1)
    println(name)
for (name in names2)
    println(name)
Daniel Hári
źródło

Odpowiedzi:

281

Tablice i listy (reprezentowane przez List<T>i jego podtyp MutableList<T>) mają wiele różnic, oto najważniejsze:

  • Array<T>jest klasą o znanej implementacji: jest to sekwencyjny region pamięci o stałym rozmiarze, przechowujący elementy (w JVM jest reprezentowany przez tablicę Java ).

    List<T>i MutableList<T>interfejsy, które mają różne implementacje: ArrayList<T>, LinkedList<T>itp reprezentacja Pamięć i operacje logika listach są zdefiniowane w konkretnej implementacji, np indeksowanie w sposób LinkedList<T>przechodzi przez linki i zajmuje O (n), natomiast czas ArrayList<T>przechowuje swoje pozycje w dynamicznie przydzielonego tablicy.

    val list1: List<Int> = LinkedList<Int>()
    val list2: List<Int> = ArrayList<Int>()
  • Array<T>jest zmienny (można go zmienić przez dowolne odniesienie do niego), ale List<T>nie ma metod modyfikujących (jest to widok tylko do odczytuMutableList<T> lub niezmienna implementacja listy ).

    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
  • Tablice mają ustalony rozmiar i nie mogą rozszerzać ani zmniejszać tożsamości zachowującej (musisz skopiować tablicę, aby zmienić jej rozmiar). Co do list, MutableList<T>ma addi removefunkcje, dzięki czemu może zwiększać i zmniejszać swój rozmiar.

    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>jest niezmienny dlaT ( Array<Int>nie jest Array<Number>), to samo dla MutableList<T>, ale List<T>jest kowariantem ( List<Int>jest List<Number>).

    val a: Array<Number> = Array<Int>(0) { 0 } // won't compile
    val l: List<Number> = listOf(1, 2, 3) // OK
  • Tablice są zoptymalizowane dla prymitywów: istnieją oddzielne IntArray, DoubleArray, CharArrayitd., Które są odwzorowane na Java prymitywnych tablic ( int[], double[], char[]), nie ramkach z nich ( Array<Int>jest mapowany do Javy Integer[]). Listy ogólnie nie mają implementacji zoptymalizowanych dla prymitywów, chociaż niektóre biblioteki (poza JDK) zapewniają listy zoptymalizowane dla prymitywów.

  • List<T>i MutableList<T>odwzorowane rodzajów i mają szczególne zachowanie interoperacyjności Java (Java List<T>widać z Kotlin jako albo List<T>albo MutableList<T>). Tablice są również mapowane, ale mają inne zasady współdziałania Java.

  • Niektóre typy tablic są używane w adnotacjach (prymitywne tablice Array<String>i tablice z enum classwpisami), a dla adnotacji istnieje specjalna składnia dosłowna . Listy i inne kolekcje nie mogą być używane w adnotacjach.

  • Jeśli chodzi o użycie, dobrą praktyką jest preferowanie używania list zamiast tablic wszędzie, z wyjątkiem krytycznych pod względem wydajności części kodu, rozumowanie jest takie samo jak w przypadku Javy .

Klawisz skrótu
źródło
26

Główną różnicą po stronie użytkowania jest to, że tablice mają stały rozmiar, a jednocześnie (Mutable)Listmogą dynamicznie dostosowywać swój rozmiar. Ponadto Arrayjest zmienny, podczas gdy Listnie jest.

Ponadto kotlin.collections.Listjest interfejsem realizowanym między innymi przez java.util.ArrayList. Można go również rozszerzyć, kotlin.collections.MutableListaby można go było użyć, gdy potrzebne są zbiory umożliwiające modyfikację przedmiotu.

Na poziomie jvm Arraysą reprezentowane przez tablice . Listz drugiej strony jest reprezentowany przez, java.util.Listponieważ w Javie nie ma dostępnych niezmiennych odpowiedników kolekcji.

miensol
źródło
Nie jestem do końca przekonany. Co można modyfikować Array? Tylko jego elementy - to samo w List. Rozmiar Listjest również ustalony.
AndroidEx
1
@AndroidEx następujące elementy będą się kompilować, val intArray = arrayOf(1,2,3); intArray[0] = 2podczas gdy nie będzie to możliwe val intList = listOf(1,2,3); intList[0] = 2. ListRzeczywiście ma stały rozmiar, ale MutableListktóra rozciąga się stąd, że nie jest to możliwe, że val a:List<Int>zgłosi inny sizena kolejnych połączeń.
miensol
Czy zaleca się używać Listlub ArrayList?
IgorGanapolsky
2
@IgorGanapolsky Jeśli nie zależy ci na konkretnej implementacji, skorzystaj List(prawdopodobnie 99% przypadków 🙂). Jeśli zależy Ci na implementacji, skorzystaj z niej ArrayListlub LinkedListinnej konkretnej implementacji.
miensol