配列
Android を触っていて色々なサイトを巡ると
配列の表記方法が異なる。
なんじゃろ・・・。
グーグル先生! 質問です!
→ Java の道:1.配列の基本
→ ひしだまのコンピュータ関連技術メモ:Java:Java 配列
結果、元々2通りの宣言方法があることがわかった。
他にもルールがあるようなので、一応まとめておく。
int[] myInt;[/java2se6] この2種類がある。
個人的には1行目の方がピンとくるのだが
Java では2行目が推奨のようなので、私はそちらを採用。
オブジェクトも配列化できる。
[android]String[] myString;[/android]
UI も配列化可能。
[android]Button[] myButton;[/android]
あ、これは Android の話かな。
Java 本家はいじってないのでわからない。
Java で配列を利用する場合は、インスタンスの生成と同時に領域を確保 しなければならない。
つまり 利用前 に領域を確保しなければならない。
[java2se6]// まず宣言し
int[] myInt;
// インスタンスの生成と同時に領域を確保(利用前に領域確保)
myInt = new int[3];
// 利用
myInt[0] = 2011;
// 宣言と同時にインスタンスの生成
int myInt = new int[3];[/java2se6]
int[3] の 3 は、3箇所確保 という意味なので
上記の例の場合は
- myInt[0]
- myInt[1]
- myInt[2]
の領域を確保したことになる。
myInt = new int[] {1, 2, 3};
myInt = {1, 2, 3}; // new int[] は省略可能
String[] myString;
myString = new String[] {“A”, “B”, “C”};
myString = {“A”, “B”, “C”}; // new String[] は省略可能
// 宣言と同時に初期化も可能
int[] myInt = new int[] {1, 2, 3};
int[] myInt = {1, 2, 3}; // new int[] は省略可能
String[] myString = new String[] {“A”, “B”, “C”};
String[] myString = {“A”, “B”, “C”}; // new String[] は省略可能[/java2se6]
こんな感じ。
{1, 2, 3} や {“A”, “B”, “C”} の部分を 配列初期化子 という。
「あれ? 3箇所確保したからって、キーは 0, 1, 2 で決定?
2, 5, 8 とかは? 連想配列は?」
すぐにこのような疑問を持った。
現段階で理解した限りでは
これが Java の仕様らしい。
- 3箇所領域確保 = キーは 0, 1, 2 で決定
- 要素数は固定
- 連想配列というものは存在しない
- 初期値が存在する(一般変数の場合は初期値なし)
もし連想配列を利用したければ、クラスを自作することになるようだ。
キーワード:Hashtable, HashMap, TreeMap
<参考サイト>
オサレマの技術メモ:JAVAプログラム 連想配列操作
japan.internet.com:Javaで作成する多次元配列操作ライブラリ
- myInt[0][0]
- myInt[0][1]
- myInt[1][0]
- myInt[1][1]
- myInt[2][0]
- myInt[2][1]
[java2se6]int[] myInt = new int[3];
int[] myInt[0] = new int[2];
int[] myInt[1] = new int[1];
int[] myInt[2] = new int[3];[/java2se6]
このようにすると、同じ多次元配列でも
2階層目の要素数が異なる多次元配列を生成できる。
と思ったら、こんなエラーが出た。
できないのかぁ。
正しい書式はこちら。
[java2se6]int[][] myInt = new int[3][];
myInt[0] = new int[2];
myInt[1] = new int[1];
myInt[2] = new int[3];[/java2se6]
- myInt[0][0]
- myInt[0][1]
- myInt[1][0]
- myInt[2][0]
- myInt[2][1]
- myInt[2][2]
配列型 | 初期値 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
char | ‘\u0000’ |
boolean | false |
参照型(オブジェクト型) | null |
引用元サイト:Java の道 1.配列の基本
配列(とコレクション)に特化した for ステートメント がある。
[java2se6]// 配列の生成
int[] myInt = {1, 2, 3};
// for (要素を受け取る変数: 配列)
for (int i: myInt) {
System.out.println(i);
}[/java2se6]
5行目 ( ) 内は、: (コロン)であって ; (セミコロン)ではない。
length プロパティは、配列の要素数を返す。
[java2se6]int[] myOdd = {1, 3, 5};
System.out.printIn(myOdd.length);
// output
// 3[/java2se6]
配列の中身を見るには
- 1次元配列 ・・・ Arrays.toString メソッド
- 多次元配列 ・・・ Arrays.deepToString メソッド
[android]// 1次元配列
int[] intArray = {1, 2, 3, 4, 5};
Log.i(“Dump”, Arrays.toString(intArray) );
// [1, 2, 3, 4, 5]
// 3次元配列
int[][][] intMultidimensionalArray = { { {1, 2, 3, 4, 5}, {6, 7, 8} }, { {11, 21, 31}, {41, 51, 61, 71, 81} } };
Log.i(“Dump”, Arrays.deepToString(intMultidimensionalArray) );
// [[[1, 2, 3, 4, 5], [6, 7, 8]], [[11, 21, 31], [41, 51, 61, 71, 81]]][/android]
static String toString(int[] a)
各データ型毎に用意されている。JDK 6 ドキュメント:Arrays toString
static String deepToString(Object[] a)
JDK 6 ドキュメント:Arrays deepToString
配列をコピーするには、以下の6種の手法がある。
- 代入演算子 =
- for ステートメント
- Object.clone メソッド
- System.arraycopy メソッド
- Arrays.copyOf メソッド ← JDK 1.6 より追加
- Arrays.copyOfRange メソッド ← JDK 1.6 より追加
コピーする際、コピー先配列について、基本的に
- コピー元より要素数が少ない場合は、足りない要素はカットされる
- コピー元より要素数が多い場合、もしくは情報がない場合は null がセットされる
int[] myOdd2 = myOdd;[/java2se6] わかりやすいw
int[] myOdd2 = new int[myOdd.length];
for (int i = 0; i < myOdd.length; i++) { myOdd2[i] = myOdd[i]; }[/java2se6]
int[] myOdd2 = (int[]) myOdd.clone();[/java2se6]
protected Object clone()
JDK 6 ドキュメント:Object clone
これは単純で素敵。
int[] myOdd2 = new int[5];
System.arraycopy(myOdd, 1, myOdd2, 3, 2);[/java2se6]
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
JDK 6 ドキュメント:System arraycopy
第1引数:コピー元配列
第2引数:コピー元配列開始位置
第3引数:コピー先配列
第4引数:コピー先配列開始位置
第5引数:コピー個数
myOdd2 の中身は、以下のようになる。
- myOdd2[0] → 0
- myOdd2[1] → 0
- myOdd2[2] → 0
- myOdd2[3] → 3
- myOdd2[4] → 5
arraycopy メソッドは、その引数を見てもわかる通り、
配列を Object クラスで認識するため、データ型があいまいになる。
(このようにクラスを親クラスとして捉えることを ダウンキャスト というらしい)
int[] myOdd2 = Arrays.copyOf(myOdd, myOdd.length);[/java2se6]
public static int[] copyOf(int[] original, int newLength)
各データ型毎に定義されている。JDK 6 ドキュメント:Arrays copyOf
第1引数:コピー元配列
第2引数:コピー元から取り出す要素数(キー 0 からいくつ分か)
int[] myOdd2 = Arrays.copyOfRange(myOdd, 1, 4);[/java2se6]
public static int[] copyOfRange(int[] original, int from, int to)
各データ型毎に定義されている。JDK 6 ドキュメント:Arrays copyOfRange
第1引数:コピー元配列
第2引数:コピー元配列開始位置
第3引数:コピー元配列終了位置
このような仕様なのだが、ちょっと勘違いしそうな点がある。
開始位置はそのままなのでいいとして
終了位置は、その手前まで という意味である。
つまり、上の例では
{1, 3, 5, 7, 9, 11} のキー 1 からキー 4 の 手前まで なので
{3, 5, 7} となり、myOdd2 の中身は、以下のようになる。
- myOdd2[0] → 3
- myOdd2[1] → 5
- myOdd2[2] → 7
手法には前述の通り3種あるが
その違いは何か。
arraycopy メソッドは、まぁ、明らかに違うとして
for ステートメントと clone メソッドの違いは何かというと
値渡しか参照渡しかの差。
- 値渡し・・・ディープコピー (Deep Copy)
for ステートメント、1次元配列の clone メソッド - 参照渡し・・・シャローコピー (Shallow Copy)
代入演算子、多次元配列の clone メソッド
というらしい。
arraycopy メソッドについては、多くのサイトでシャローコピーであると書いてあるが
私の実験結果ではディープコピーであった。なんでだろ。
配列コピーの検証
参考元サイトによると
forループを使用した場合はループ内の実装方法の違い
(新たなインスタンスを生成するか(ディープ)、
代入演算子=によりコピーを行うか(シャロー)。)
によりディープコピーにもなりますし、シャローコピーにもなります。
どちらの方法を使用するかはケースにより異なります。引用元サイト:Java の道:2.配列のコピー 配列のコピーの注意点
copyOf, copyOfRange メソッドについては、Android が J2SE5 相当のため実験できず。
コピー方式についても不明。
またそのうち実験してみよう。