IntArray vs Array <Int> w Kotlin

88

Nie jestem pewien, jaka jest różnica między an IntArrayi an Array<Int>w Kotlinie i dlaczego nie mogę ich używać zamiennie:

opuścić mecz

Wiem, że to się IntArrayprzekłada, int[]gdy kierujemy na JVM, ale co się Array<Int>przekłada?

Możesz także mieć String[]lub YourObject[]. Dlaczego Kotlin ma klasy tego typu, {primitive}Arrayskoro w tablicy można umieścić prawie wszystko, nie tylko prymitywy.

FRR
źródło
1
Moje przypuszczenie to, że Array<Int>gromadzi do Integer[](jeśli kompilator nie zoptymalizować)
MiBAC
Tak, to ma sens, dziękuję wam obojgu!
FRR

Odpowiedzi:

107

Array<Int>jest Integer[]pod maską, a IntArrayjest int[]. Otóż ​​to.

Oznacza to, że jeśli umieścić Intw sposób Array<Int>, to zawsze będzie ramkach (w szczególności z Integer.valueOf()połączenia). W przypadku IntArrayformatu boksowanie nie nastąpi, ponieważ przekłada się to na tablicę prymitywną języka Java.


Poza możliwymi konsekwencjami powyższego dla wydajności, należy wziąć pod uwagę również wygodę. Tablice prymitywne mogą pozostać niezainicjowane i będą miały 0wartości domyślne we wszystkich indeksach. Oto dlaczego, IntArraya pozostałe tablice pierwotne mają konstruktory, które przyjmują tylko parametr rozmiaru:

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

W przeciwieństwie do tego, Array<T>nie ma konstruktora, który przyjmuje tylko parametr rozmiaru: potrzebuje prawidłowych, niezerowych Twystąpień we wszystkich indeksach, aby były w prawidłowym stanie po utworzeniu. W przypadku Numbertypów może to być ustawienie domyślne 0, ale nie ma możliwości tworzenia domyślnych instancji dowolnego typu T.

Tak więc podczas tworzenia Array<Int>możesz użyć konstruktora, który również przyjmuje funkcję inicjalizującą:

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

Lub utwórz ankietę, Array<Int?>aby uniknąć konieczności inicjowania każdej wartości, ale później będziesz zmuszony radzić sobie z możliwymi nullwartościami za każdym razem, gdy czytasz z tablicy.

val arr = arrayOfNulls<Int>(10)
zsmb13
źródło
4
To dość głupia decyzja. Z tego powodu musieli stworzyć nową klasę dla każdego typu pierwotnego ... Mogli po prostu używać tej samej, co w Javie.
programista Androida
1
@androiddeveloper Jaka nowa klasa? int[]jest IntArray, Integer[]jest Array<Int>i tak dalej, gdzie jest ta tajemnicza nowa klasa? To ta sama rzecz, tylko składnia jest inna. int[]Nawiasem mówiąc, to także klasa.
Eugen Pechanec
1
@EugenPechanec To jest interesujące. Mówią, że jest to klasa i ma instancję, ale także „instancje tej klasy są reprezentowane jako int []”: kotlinlang.org/api/latest/jvm/stdlib/kotlin/-int-array/… . Czy te funkcje są tylko funkcjami rozszerzającymi, czy też należą do prawdziwej klasy? I dlaczego trzeba było mieć „IntArray” i inne? Nadal można to zrobić za pomocą składni Java.
programista Androida
1
@EugenPechanec Ale w Javie int [] nie jest klasą, prawda? To obiekt, tablica prymitywów. Nie możesz dotrzeć do kodu, ani go rozszerzyć. Nie? Wszystkie klasy w Javie mają przy nazwie wielką literę. Tutaj go nie ma.
programista Androida
1
@EugenPechanec Tak więc w Kotlinie jest to klasa, podczas gdy w Javie nie. Nadal nie rozumiem, dlaczego. Mogliby po prostu dodać funkcje rozszerzeń, nie? Może możesz przedłużyć z IntArray? O nazewnictwie, wiem. To tylko konwencja i też dobra.
programista Androida
6

Warto zauważyć, że użycie *operatora spread ( ) na a varargzwróci IntArray. Jeśli potrzebujesz Array<Int>, możesz przekonwertować plik IntArrayusing .toTypedArray().

Eran Boudjnah
źródło
1

Tablice w Kotlinie są klasami (nie typami „specjalnymi”, takimi jak Java).

Stdlib Kotlina zapewnia klasy specjalnego przeznaczenia dla tablic prymitywnych JVM w celu poprawy integracji i wydajności języka Java.

Praktyczną zasadą jest użycie Array<T>z wyjątkiem sytuacji, gdy powoduje to problem podczas mieszania z istniejącym kodem Java lub powinno być wywoływane z klas Java. Dla przypomnienia, nigdy nie musiałem używać IntArray.

Możesz sprawdzić dokumentację języka dotyczącą tej sprawy tutaj: https://kotlinlang.org/docs/reference/basic-types.html#arrays

jaguililla
źródło
Uważam, że masz rację, zawsze faworyzując Array <T> nad IntArray, martwiłem się o narzuty związane z boksowaniem / rozpakowywaniem w porównaniu z typem pudełkowym w porównaniu z prymitywem, ale wydaje się, że Kotlin jest wystarczająco inteligentny, aby zdecydować, czy może użyć prymitywu, czy nie . (Popraw mnie, jeśli się mylę) „Na platformie Java liczby są fizycznie przechowywane jako typy prymitywów maszyny JVM, chyba że potrzebujemy odwołania do liczby null (np. Int?) Lub są to typy ogólne. W tych ostatnich przypadkach liczby są umieszczane w ramkach”. Z kotlinlang.org/docs/reference/basic-types.html
FRR,
@feresr nie ekspertem w jakikolwiek sposób, ale myślę, że odnosi się tylko do implementacji Int, Floatitp, ponieważ Kotlin nie posiada innego rodzaju na Booleanlub boolean. Pod względem tablic zakładałbym, Array<Int>że różni się od IntArray. Osobiście zawsze używałem tego ostatniego, ponieważ nigdy mi to nie przeszkadzało, ale może Kotlin ma dodatkową optymalizację, której nie jestem świadomy. Jeśli programujesz wyłącznie w kotlinie, nie widzę żadnego przypadku, w którym potrzebujesz jednego nad drugim, ale prymitywna tablica może nadal mieć swoje zalety.
Allan W.
@Allan też nie jest ekspertem, po prostu ciekawy, uważam, że java ma zarówno prymitywy, jak i obiekty w pudełkach, ponieważ bardziej wydajna jest praca z prymitywami, prawda ?, oczywiście czasami naprawdę trzeba pracować z obiektem (nullability / generics). To wykracza poza zakres mojego pierwotnego pytania, ale zastanawiam się, jak radzi sobie z tym Kotlin, kierując się na JVM. Staram się używać IntArray, kiedy tylko jest to możliwe (myśląc, że używa prymitywów pod maską), ale po komentarzu @ jamming nie jestem już pewien.
FRR
1
@feresr dla mnie, dokumentacja Kotlina wyraźnie stwierdza, że ​​specjalne instancje tablic istnieją, aby uniknąć narzutu związanego z boksowaniem. Moim wnioskiem jest to, że oba są prawdopodobnie różne, i ostatecznie dla programisty staje się to tym samym, co decyzja, czy chcesz używać Integer [] czy int [] w Javie.
Allan W.
Zgadzam się, wtedy zaakceptowana odpowiedź może być odrobinę myląca dla nowo przybyłych, z tego powodu odznaczam ją jako zaakceptowaną.
FRR