IntArray против Array <Int> в Котлине


88

Я не уверен, в чем разница между an IntArrayи an Array<Int>в Kotlin и почему я не могу использовать их взаимозаменяемо:

несовпадение

Я знаю , что IntArrayпереводится int[]в информировании JVM, но что Array<Int>переводить?

Кроме того, вы также можете иметь String[]или YourObject[]. Почему в Kotlin есть классы такого типа, {primitive}Arrayкогда в массив можно упорядочить практически все, а не только примитивы.


1
Я предполагаю , что это Array<Int>компилируется в Integer[](если компилятор не оптимизирует это)
Mibac


Да, в этом есть смысл, спасибо вам обоим!
FRR

Ответы:


107

Array<Int>находится Integer[]под капотом, а IntArrayэто int[]. Вот и все.

Это означает, что когда вы помещаете Intв Array<Int>, он всегда будет помещен в рамку (в частности, с Integer.valueOf()вызовом). В этом случае IntArrayупаковки не произойдет, поскольку она преобразуется в примитивный массив Java.


Помимо возможных последствий для производительности из вышеперечисленного, следует также учитывать удобство. Примитивные массивы можно оставить неинициализированными, и они будут иметь 0значения по умолчанию для всех индексов. Вот почему IntArrayи остальные примитивные массивы имеют конструкторы, которые принимают только параметр размера:

val arr = IntArray(10)
println(arr.joinToString()) // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0

Напротив, у Array<T>него нет конструктора, который принимает только параметр размера: ему нужны действительные ненулевые Tэкземпляры во всех индексах, чтобы они находились в допустимом состоянии после создания. Для Numberтипов это может быть значение по умолчанию 0, но нет способа создать экземпляры произвольного типа по умолчанию T.

Поэтому при создании Array<Int>вы можете использовать конструктор, который также принимает функцию инициализатора:

val arr = Array<Int>(10) { index -> 0 }  // full, verbose syntax
val arr = Array(10) { 0 }                // concise version

Или создайте, Array<Int?>чтобы избежать инициализации каждого значения, но позже вам придется иметь дело с возможными nullзначениями каждый раз, когда вы читаете из массива.

val arr = arrayOfNulls<Int>(10)

4
Это довольно глупое решение. Из-за этого им пришлось создать новый класс для каждого примитивного типа ... Они могли просто использовать то же, что и на Java.
разработчик Android

1
@androiddeveloper Какой новый класс? int[]есть IntArray, Integer[]есть Array<Int>и так далее, где этот таинственный новый класс? То же самое, только синтаксис другой. int[]тоже класс, кстати.
Eugen Pechanec

1
@EugenPechanec Это интересно. Они говорят, что это класс и что у него есть экземпляр, но также «экземпляры этого класса представлены как int []»: kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int-array/… . Итак, являются ли эти функции просто функциями расширения или они относятся к реальному классу? А зачем было иметь «IntArray» и другие? Все еще может быть сделано с использованием синтаксиса Java.
разработчик Android

1
@EugenPechanec Но в Java int [] - это не класс, не так ли? Это объект, массив примитивов. Вы не можете получить доступ к коду или расширить его. Нет? Все классы на Java имеют в своем имени заглавную букву. Здесь это не так.
разработчик Android

1
@EugenPechanec Итак, на Kotlin это класс, а на Java - нет. Все еще не понимаю, почему. Они могут просто добавить функции расширения, не так ли? Возможно, вы можете перейти от IntArray? Насчет наименования я знаю. Это просто соглашение, и тоже хорошее.
разработчик Android

6

Стоит отметить, что использование *оператора spread ( ) для varargобъекта вернет IntArray. Если вам нужен Array<Int>, вы можете преобразовать свой IntArrayusing .toTypedArray().


1

Массивы в Kotlin - это классы (а не «особые» типы, такие как Java).

Stdlib Kotlin предоставляет классы специального назначения для массивов примитивов JVM, чтобы улучшить интеграцию и производительность языка Java.

Эмпирическое правило должно использоваться, Array<T>кроме случаев, когда оно вызывает проблему при смешивании с существующим кодом Java или должно вызываться из классов Java. Для справки, мне никогда не приходилось использовать IntArray.

Вы можете проверить документацию по языку по этому поводу здесь: https://kotlinlang.org/docs/reference/basic-types.html#arrays


Я считаю, что вы правы, всегда отдавая предпочтение Array <T> вместо IntArray, я беспокоился о накладных расходах на упаковку / распаковку при использовании коробочного типа против примитива, но кажется, что Kotlin достаточно умен, чтобы решить, может ли он использовать примитив или нет . (Поправьте меня, если я ошибаюсь) «На платформе Java числа физически хранятся как примитивные типы JVM, если нам не нужна ссылка на число, допускающее значение NULL (например, Int?), Или используются обобщенные типы. В последних случаях числа заключены в рамки». От kotlinlang.org/docs/reference/basic-types.html
FRR

@feresr не специалист любых средств, но я думаю , что это только со ссылкой на реализации Int, Floatи т.д., учитывая , что Котлин не имеет другой типа для Booleanили boolean. Что касается массивов, я бы предположил, что это Array<Int>будет отличаться от IntArray. Я лично всегда использовал последнее, так как меня это никогда не беспокоило, но, возможно, в Kotlin есть дополнительная оптимизация, о которой я не знаю. Если вы программируете исключительно на kotlin, я не вижу случаев, когда вам нужен один над другим, но примитивный массив может иметь свои преимущества.
Allan W

@AllanW тоже не эксперт, просто любопытно, я считаю, что в java есть как примитивы, так и объекты в штучной упаковке, потому что с примитивами работать эффективнее, верно? Конечно, иногда вам действительно нужно работать с объектом (допустимость значений NULL / обобщения). Это выходит за рамки моего первоначального вопроса, но мне интересно, как Kotlin справляется с этим при нацеливании на JVM. Я стараюсь использовать IntArray, когда это возможно (думая, что он использует примитивы под капотом), но после комментария @ jamming я больше не уверен.
FRR

1
@feresr для меня, в документации Kotlin явно указано, что специальные экземпляры массива существуют, чтобы избежать накладных расходов на бокс. Мой вывод заключается в том, что они, вероятно, разные, и в конечном итоге для разработчика это то же самое, что решить, хотите ли вы использовать Integer [] или int [] в Java.
Allan W

Я согласен, тогда принятый ответ может немного ввести в заблуждение новичков, по этой причине я снимаю этот флажок как принятый.
FRR
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.