Разница между типами List и Array в Котлине
В чем разница между 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)
5 ответов
Массивы и списки (представлены 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>
сопоставлен с JavaInteger[]
). Как правило, списки не имеют реализаций, оптимизированных для примитивов, хотя некоторые библиотеки (за пределами JDK) предоставляют списки, оптимизированные для примитивов.List<T>
а такжеMutableList<T>
являются сопоставленными типами и имеют особое поведение в совместимости Java (Java'sList<T>
видно из Котлина какList<T>
или жеMutableList<T>
). Массивы также отображаются, но у них есть другие правила взаимодействия Java.Определенные типы массивов используются в аннотациях (примитивные массивы,
Array<String>
и массивы сenum class
записи), и есть специальный синтаксис литерала массива для аннотаций. Списки и другие коллекции не могут быть использованы в аннотациях.Что касается использования, то хорошей практикой является предпочтение использования списков, а не массивов везде, кроме критически важных для вашего кода частей, причина которых та же, что и для Java.
Основное отличие от использования состоит в том, что массивы имеют фиксированный размер, а (Mutable)List
можно настроить их размер динамически. более того Array
изменчиво, тогда как List
не является.
более того kotlin.collections.List
это интерфейс, реализованный среди других java.util.ArrayList
, Это также продлено kotlin.collections.MutableList
используется, когда необходимы коллекции, которые позволяют модифицировать элемент.
На уровне jvm Array
представлен массивами. List
с другой стороны, представлен java.util.List
поскольку в Java нет неизменных эквивалентов коллекций.
В дополнение к вышесказанному, сравнение идентичности также отличается:
val l1 = listOf("a")
val l2 = listOf("a")
var x = (l1 == l2) // => true
val a1 = arrayOf("a")
val a2 = arrayOf("a")
var y = (a1 == a2) // => false
Объяснение со сложным объектом
// lets define a data class
data class Color(var name : String)
// lets define all 3 - array, list and mutableList for this Color object
val array = arrayOf(Color("Red"))
val list = listOf(Color("Red"))
val mutableList = mutableListOf(Color("Red"))
- Методы в массиве
array.add(Color("Green")) // Not Possible - cannot change size
array[0] = Color("Green") // Possible - array object can be changed
array[0].name = "Green" // Possible - object modification allowed by its class
- Методы в списке
list.add(Color("Green")) // Not Possible - cannot change size
list[0] = Color("Green") // Not Possible - list object cannot be changed
list[0].name = "Green" // Possible - object modification allowed by its class
- Методы в mutableList
mutableList.add(Color("Green")) // Possible - can change size
mutableList[0] = Color("Green") // Possible - can change object
mutableList[0].name = "Green" // Possible - object modification allowed by its class
Выводы :
- массивы и списки имеют фиксированный размер, поэтому вы не можете добавлять или удалять элементы.
- список не может быть изменен, что означает, что вы не можете изменить объект, который он содержит.
- массив можно изменить, что означает, что вы можете изменить объект, который он содержит.
- mutableList может делать что угодно, изменять размер или свои объекты
ПРИМЕЧАНИЕ. Это ничего не указывает на изменчивость самого объекта. т.е. если класс данных имеет какое-то свойство как изменяемое (var), его свойство можно изменить.
** В общем, различия между типами List и Array: **
List<...>:
только для чтения.
Array<...>:
Вы можете изменить это, или добавить что-то.