search
LoginSignup
25

More than 3 years have passed since last update.

Organization

Kotlin: IntArray と Array<Int> の違い

JVMコンパイルの場合の話です。

IntArrayArray<Int> は似たように使えますが、 似て非なるものです。 IntArray のほうが、スピードが速いです。 (IntArray のほかにも CharArray, BooleanArray, LongArray, ShortArray, ByteArray が Kotlin には用意されています。)

どれくらい似ているのか

瓜二つです。

IntArray
public class IntArray(size: Int) {
    public inline constructor(size: Int, init: (Int) -> Int)
    public operator fun get(index: Int): Int
    public operator fun set(index: Int, value: Int): Unit
    public val size: Int
    public operator fun iterator(): IntIterator
}
Array
public class Array<T> {
    public inline constructor(size: Int, init: (Int) -> T)
    public operator fun get(index: Int): T
    public operator fun set(index: Int, value: T): Unit
    public val size: Int
    public operator fun iterator(): Iterator<T>
}

どこが違うのか

Kotlin のドキュメントにもありますが、 IntArray は Java でいうところの int[] を表したもの、 Array<Int> は Java の Integer の Array です。

逆アセンブル見てみると違いがわかります。 宣言時に、 INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer という記述があります。 Array<Int> では、 ボクシングをするため オーバヘッドが生じています。

補足: ボクシング

Boxing(ボクシング)は Java のプリミティブ型から参照型オブジェクトを作成することをいいます。 Java では int などの基本型があり、 基本型のラッパーとして参照型 Integer があります。 参照型としてラップしてオブジェクトにすると、メソッドを使うことができます。 単純なものでは、 inttoString() はなく、 Integer には toString() があります。 参照型オブジェクトからプリミティブ型の値を取り出すことを Unboxing(アンボクシング)といいます。
C# でも値型とオブジェクト型があり、ボクシング・アンボクシングがあります。

Test.kt
val a = intArrayOf(1, 2, 3) // IntArray
val b = arrayOf(1, 2, 3)    // Array<Int>

逆アセンブルすると次のようになります。 よく見ると、 arrayOf では java.lang.Integer のインスタンスを生成して配列にしているのがわかりますね。

// ================TestKt.class =================
// class version 50.0 (50)
// access flags 0x31
public final class TestKt {


  // access flags 0x1A
  private final static [I a
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x19
  public final static getA()[I
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 4 L0
    GETSTATIC TestKt.a : [I
    ARETURN
   L1
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x1A
  private final static [Ljava/lang/Integer; b
  @Lorg/jetbrains/annotations/NotNull;() // invisible

  // access flags 0x19
  public final static getB()[Ljava/lang/Integer;
  @Lorg/jetbrains/annotations/NotNull;() // invisible
   L0
    LINENUMBER 5 L0
    GETSTATIC TestKt.b : [Ljava/lang/Integer;
    ARETURN
   L1
    MAXSTACK = 1
    MAXLOCALS = 0

  // access flags 0x8
  static <clinit>()V
   L0
    LINENUMBER 4 L0
    ICONST_3
    NEWARRAY T_INT
    DUP
    ICONST_0
    ICONST_1
    IASTORE
    DUP
    ICONST_1
    ICONST_2
    IASTORE
    DUP
    ICONST_2
    ICONST_3
    IASTORE
    PUTSTATIC TestKt.a : [I
   L1
    LINENUMBER 5 L1
    ICONST_3
    ANEWARRAY java/lang/Integer
    DUP
    ICONST_0
    ICONST_1
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    AASTORE
    DUP
    ICONST_1
    ICONST_2
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    AASTORE
    DUP
    ICONST_2
    ICONST_3
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    AASTORE
    PUTSTATIC TestKt.b : [Ljava/lang/Integer;
    RETURN
    MAXSTACK = 4
    MAXLOCALS = 0

  @Lkotlin/Metadata;(mv={1, 1, 10}, bv={1, 0, 2}, k=2, d1={"\u0000\u0016\n\u0000\n\u0002\u0010\u0015\n\u0002\u0008\u0003\n\u0002\u0010\u0011\n\u0002\u0010\u0008\n\u0002\u0008\u0004\"\u0011\u0010\u0000\u001a\u00020\u0001\u00a2\u0006\u0008\n\u0000\u001a\u0004\u0008\u0002\u0010\u0003\"\u0019\u0010\u0004\u001a\u0008\u0012\u0004\u0012\u00020\u00060\u0005\u00a2\u0006\n\n\u0002\u0010\u0009\u001a\u0004\u0008\u0007\u0010\u0008\u00a8\u0006\n"}, d2={"a", "", "getA", "()[I", "b", "", "", "getB", "()[Ljava/lang/Integer;", "[Ljava/lang/Integer;", "production sources for module test_main"})
  // compiled from: Test.kt
}

変換するには

Test.kt
val a = intArrayOf(1, 2, 3) // IntArray
val b = arrayOf(1, 2, 3)    // Array<Int>

このように定義した2種類の配列を、 a = b または b = a のようにすることはできません。 toTypedArray, toIntArray を使います。

a = b.toIntArray()
b = a.toTypedArray()

パフォーマンスの差

やってみた

処理時間の比較は次の通りとなりました。

処理時間
IntArray 955
Array 3437

比較に使ったのは次のコードです。 100要素の配列を作るというのをなんども繰り返して合計でかかった時間を処理時間としています。

var cost = 0L
repeat(10) {
    cost += kotlin.system.measureTimeMillis {
        repeat(1000000) {
            IntArray(100) { 1 }
        }
    }
} 
println(cost)
// => 955
var cost = 0L
repeat(10) {
    cost += kotlin.system.measureTimeMillis {
        repeat(1000000) {
            Array(100) { 1 }
        }
    }
} 
println(cost)
// => 3437

他のデータ

Gist にデータがありました。 Kotlin Merge SortIntArray はボクシングとアンボクシングの手間が省かれているため、速いです。 マージソートでの比較では IntArray を使うと、 Array<Int> の 1/2以下の時間でソートができているそうです。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
25