Kotlin基本体和对象数组

Kotlin Primitive and Object Arrays

我最初打算写这篇文章是因为我在玩一些反射代码,并认为自己发现了一些有趣的东西。 las,绝对不是这样。 相反,它只是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字节码中编译为LongLong。 编译的类型取决于字段的可为空性。 数组更明确,因此编译时它们的类型不会改变。

为了避免这种情况,Kotlin提供了一些选择,这些类在向下编译为JVM字节码时变为原始数组。

这些类包括:

对于无符号类型的数组,还有其他类。

这些类也可以在Kotlin和Java之间互换,而无需付出任何额外的努力。

作为最后的证据,向您展示Kotlin中原始数组与包装的/对象数组之间的区别,我想向您展示一些Kotlin代码,这些代码已转换为Java对应的代码:

1
2
3
4
5
6
7
8
9
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字节码反编译器,该代码段反编译为:

1
2
3
4
5
6
7
8
9
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,所以这些都不重要。

现在,您应该对LongArray之类的原始数组与诸如Array<Long>之类的对象数组之间的区别有了更好的了解。 如果不是,那么我让你失败了,对此我深表歉意。

如果您认为这篇文章有帮助,可以在Twitter上@LankyDanDev关注我,以跟上我的新文章。