LoginSignup
12
19

More than 5 years have passed since last update.

[Java] 配列のメモ

Last updated at Posted at 2015-10-23

目的

Javaの配列を扱うメソッドはいくつかのクラスに分散しているので、整理してみます。
各メソッドの詳細な説明はしません。

基本的なこと

  • 配列はオブジェクト
  • 多次元配列は、配列の配列であらわす
  • 配列は共変(covariant)
  • Iterableではないけど、拡張forループに使用可能

配列のシャローコピー

既にある配列に全体、あるい一部をコピー

java.lang.System#arraycopy()

同じ配列インスタンスを新しく生成

配列オブジェクト.clone()

  • キャスト不要
  • CloneNotSupportedExceptionもキャッチ不要
private int[] values;

public void setValues(int[] values) {
    // 防御的コピー
    this.values = values.clone();
}

サイズを指定して、あるいは部分配列を新しく生成

  • java.util.Arrays#copyOf()
  • java.util.Arrays#copyOfRange()

配列のリスト化

java.util.Arrays#asList()

  • リストのサイズが変わる操作は不可(add,remove,clearなど)
  • 要素の値が変わる操作はOK。 リストの要素を変えると、配列の要素も変わる
  • 要素がプリミティブ型の場合には、可変引数で渡すことはできるけど、配列として渡すことはできないので注意。

プリミティブ型配列のリスト化(案)

必要なプリミティブ型配列用の、以下のようなユーティリティメソッドを用意すればよいのかな。毎回オートボクシングがはしるけど。

public static List<Integer> asList(final int[] array) {
    return new AbstractList<Integer>() {
        @Override
        public Integer get(int index) {
            return array[index];
        }

        @Override
        public Integer set(int index, Integer element) {
            int oldValue = array[index];
            array[index] = element;
            return oldValue;
        }

        @Override
        public int size() {
            return array.length;
        }
    };
}

※本当は java.util.RandomAccess を実装するべきかな。

リストの配列化

  • java.util.List#toArray()
  • java.util.List#toArray(T[])

例1:

List<String> list = getList();

// 引数無しは Object[] を返す
Object[] array = list.toArray();

例2:

// 十分なサイズの配列を渡せば、その配列が返ってくる
String[] strings = list.toArray(new String[list.size()]);

例3:

private static final String[] EMPTY_STRINGS = new String[0];

// ...

// サイズが足りない場合には、新しい配列を生成して返してくれる
String[] strings = list.toArray(EMPTY_STRINGS);

配列とストリームの相互変換

  • java.util.Arrays#stream() - 配列のストリーム化
  • java.util.stream.Stream#toArray() - ストリームの配列化

プリミティブ型の対応もあり(IntStream#toArray()とか)。

リフレクション

配列オブジェクトのlengthフィールドやclone()メソッドは、Class#getDeclaredFields() や Class#getDeclaredMethods() 等では取得できないようです。

その代わりに、配列をリフレクションで扱うための java.lang.reflect.Array クラスがあります。

オブジェクトが配列かどうか判定

java.lang.Class#isArray()

配列の要素の型を取得

java.lang.Class#getComponentType()

配列の長さを取得

java.lang.reflect.Array#getLength()

配列の要素を取得、設定

  • java.lang.reflect.Array#get()
  • java.lang.reflect.Array#set()

プリミティブ型を get(), set() で扱うとオートボクシング/アンボクシングされます。
プリミティブ型用の getInt(), getLong(), setInt(), setLong() などもあります。

配列の生成

java.lang.reflect.Array#newInstance()

配列の文字列化

配列オブジェクトの toString() メソッドは、Objectクラスのものと同様です。
配列の内容を表示したい場合などは、java.util.Arraysのメソッドを利用すると便利です。

  • 1次元配列 java.util.Arrays#toString()
  • 多次元配列 java.util.Arrays#deepToString()

ただし deepToString() に渡した配列オブジェクトが、自己循環参照をしている配列だった場合には、大変なことになります。
(スタックオーバーフローとか、無限ループとか)

ソート

ソートは、java.util.Arraysクラスのメソッドで可能です。

  • java.util.Arrays#sort()
  • java.util.Arrays#parallelSort()

シャッフル

ソートと同様に java.util.Arrays#asList() と java.util.Colllections#shuffle() を組み合わせて実現可能です。

List<String> list = Arrays.asList(array);
Collections.shuffle(list);

プリミティブ型の場合には、自力でがんばるしかないかも。

その他

その他のユーティリティ系メソッドは、基本的に java.util.Arrays クラスにあります。

  • fill : 値埋め
  • equals : 一致チェック
  • deepEquals : ネスト配列の一致チェック
  • binarySearch : バイナリサーチ(ソート済みである必要あり)
  • hashCode : ハッシュ値計算
  • deepHashCode : ネスト配列のハッシュ値計算

配列オブジェクトの equals() および hashCode() は Object クラスの実装と同じであるため、必要であれば上記 Arrays#equals() や Arrays#hashCode() などを利用してください。

また deep~() 系メソッドには、自己循環参照を渡さないようにする必要があります。

配列クラスの名前

配列クラスの各種名前を取得してみると、以下のような感じ。

Integer[][] array = new Integer[0][0];
Class<?> clazz = array.getClass();
System.out.println("Name         : " + clazz.getName());
System.out.println("SimpleName   : " + clazz.getSimpleName());
System.out.println("CanonicalName: " + clazz.getCanonicalName());
System.out.println("TypeName     : " + clazz.getTypeName());
Name         : [[Ljava.lang.Integer;
SimpleName   : Integer[][]
CanonicalName: java.lang.Integer[][]
TypeName     : java.lang.Integer[][]

0件の配列

一般的に配列は値の書き換えが可能なため、(仮に final にしても)修正可能オブジェクトになります。

ただし0件の配列は変更可能な部分が存在しないので、イミュータブルオブジェクトです。
そのため、定数として扱ったり、マルチスレッドで共有使用しても問題ありません。

private static final Object[] EMPTY_OBJS = new Object[0];

ビットあるいは真偽値の配列

java.util.BitSet のほうがメモリ効率は良いはず。

12
19
0

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
  3. You can use dark theme
What you can do with signing up
12
19