Я изначально намеревался написать этот пост, потому что я играл с некоторым кодом отражения и думал, что нашел что-то интересное. Увы, это точно не тот случай. Вместо этого это была просто базовая функция Kotlin, которую мне еще не нужно было использовать или на которой я должен сосредоточиться. Хотя этот пост оказался не таким, каким я хотел его видеть, я все же думаю, что это хороший небольшой пост, чтобы внести некоторую ясность в эту тему.
В Java есть концепция примитивных типов и их упакованных версий . Благодаря автобоксам и распаковкам типы могут меняться между их примитивными и упакованными версиями. Другими словами, в большинстве ситуаций вы можете использовать long
вместо Long
или Long
вместо long
. Если вы не заметили, где в последнем предложении были заглавные буквы, тогда я думаю, что это выглядело довольно странно. Формулировка в этом предложении также имеет решающее значение. Более конкретно, заявление «в большинстве ситуаций».
Автобокс и распаковка не работает при попытке поменять примитивный массив и обернутый ( Object
) массив. Например,
1
2
3
4
5
6
7
8
9
|
public class PrimitiveArrays { public static void main(String args[]) { Long[] longArray = new Long[] {1L, 2L, 3L}; takesInPrimitiveLongArray(longArray); } static void takesInPrimitiveLongArray( long [] array) {} } |
Это не работает, и попытка его скомпилировать приводит к следующей ошибке:
1
2
|
error: incompatible types: Long[] cannot be converted to long [] takesInPrimitiveLongArray(longArray); |
Переключение метода на Long[]
и передача long[]
также не скомпилируется по тем же причинам. Это не то, что большинство разработчиков Java найдет интересным, но помогает заложить основу для реального содержания этого поста.
Kotlin должен предоставить вам эквивалент примитивных массивов Java. Но Kotlin не позволяет вам определять массивы, используя тот же синтаксис, что и в Java. В Kotlin инициализация массива выглядит так:
1
2
3
|
val array = Array<Long>( 3 ) // or val array: Array<Long> = arrayOf( 1 , 2 , 3 ) |
Тот факт, что вы можете видеть, что Array
использует обобщенные элементы, должен подчеркнуть, что он не является примитивным массивом. Это факт как в Java, так и в Kotlin, что универсальные типы не могут быть примитивами. В противном случае это можно было бы отключить для Array<long>
, и мы все были бы счастливы. Приведенный выше код компилируется в массив объектов Long[]
вместо примитива long[]
.
Эта ситуация несколько уникальна для массивов. Сам по себе Kotlin Long
может компилироваться в байт-код JVM либо в Long
либо в Long
. Скомпилированный тип зависит от обнуляемости поля. Массивы более явные, поэтому их типы не изменятся при компиляции.
Чтобы обойти это, Kotlin предоставляет набор классов, которые становятся примитивными массивами при компиляции в байт-код JVM.
Эти классы включают в себя:
Котлин | Ява |
---|---|
ByteArray | байт[] |
CharArray | символ [] |
ShortArray | короткая[] |
INTArray | ИНТ [] |
LongArray | долго[] |
DoubleArray | двойной [] |
FloatArray | плавать [] |
BooleanArray | логическое [] |
Есть также дополнительные классы для массивов беззнаковых типов.
Эти классы также можно обменивать между Kotlin и Java без каких-либо дополнительных усилий.
В качестве последнего доказательства, показывающего различия между массивами примитивов и массивов / объектов в Kotlin, я хочу показать вам некоторый код Kotlin, который преобразуется в его Java-аналог:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
@file :JvmName( "PrimitiveArrays" ) package dev.lankydan fun main(args: Array<String>) { // long and Long arrays val longArray = longArrayOf( 1 , 2 , 3 , 4 ) val arrayOfLongs = arrayOf<Long>( 1 , 2 , 3 , 4 ) // int and Integer arrays val intArray = intArrayOf( 1 , 2 , 3 , 4 ) val arrayOfInts = arrayOf<Int>( 1 , 2 , 3 , 4 ) // boolean and Boolean arrays val booleanArray = booleanArrayOf( true , false ) val arrayOfBooleans = arrayOf<Boolean>( true , false ) // char and Character arrays val charArray = charArrayOf( 'a' , 'b' , 'c' ) val arrayOfChars = arrayOf<Char>( 'a' , 'b' , 'c' ) } |
Используя декомпилятор байт-кода Intellij Kotlin, фрагмент декомпилируется для:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
public final class PrimitiveArrays { public static final void main(String[] args) { Intrinsics.checkParameterIsNotNull(args, "args" ); // long and Long arrays long [] var10000 = new long []{1L, 2L, 3L, 4L}; Long[] var9 = new Long[]{1L, 2L, 3L, 4L}; // int and Integer arrays int [] var10 = new int []{ 1 , 2 , 3 , 4 }; Integer[] var11 = new Integer[]{ 1 , 2 , 3 , 4 }; // boolean and Boolean arrays boolean [] var12 = new boolean []{ true , false }; Boolean[] var13 = new Boolean[]{ true , false }; // char and Character arrays char [] var14 = new char []{ 'a' , 'b' , 'c' }; Character[] var15 = new Character[]{ 'a' , 'b' , 'c' }; } } |
Во-первых, обратите внимание, что Kotlin предоставляет вам полезные функции инициализации для ваших массивов. Как для примитивных, так и для объектных массивов. Во-вторых, как они составлены. Например, LongArray
становится long[]
а Array<Long>
становится Long[]
.
Теперь вы можете увидеть различия между этими массивами. Но я не упомянул, какие из них вы должны использовать. Вы должны откладывать примитивные типы так же, как это делает Java. Это связано с влиянием на производительность, которое могут иметь автобокс и распаковка для вашего приложения.
Для небольших рабочих нагрузок результат, вероятно, будет незначительным. С другой стороны, для больших массивов в приложениях, критичных к производительности, это небольшое изменение может иметь заметный эффект. Еще немного информации на эту тему можно найти здесь .
Если вам нужно хранить пустые значения в ваших массивах, вам все равно придется обращаться к массиву с оболочкой / объектом. В большинстве ситуаций, я думаю, вы должны быть в состоянии использовать примитивные массивы, но всегда будут времена, когда вы не сможете. При этом, как правило, мы все просто используем List
s, поэтому ничего из этого не имеет значения.
Теперь вы должны лучше понимать различия между примитивными массивами, такими как LongArray
и объектными массивами, такими как Array<Long>
. Если нет, то я подвел тебя, и я прошу прощения за это.
Опубликовано на Java Code Geeks с разрешения Дэна Ньютона, партнера нашей программы JCG . Смотреть оригинальную статью здесь: примитивные и объектные массивы Kotlin Мнения, высказанные участниками Java Code Geeks, являются их собственными. |