配列

Posted by muchag | Java |
初回投稿:2011-04-19 (火) 12:40:34 | 最終更新:2011-04-20 (水) 18:21:45

Android を触っていて色々なサイトを巡ると
配列の表記方法が異なる。
なんじゃろ・・・。

グーグル先生! 質問です!
→ Java の道:1.配列の基本
→ ひしだまのコンピュータ関連技術メモ:JavaJava 配列

結果、元々2通りの宣言方法があることがわかった。
他にもルールがあるようなので、一応まとめておく。
 

宣言
  1. int myInt[];
  2. int[] myInt;

この2種類がある。

個人的には1行目の方がピンとくるのだが
Java では2行目が推奨のようなので、私はそちらを採用。
 

オブジェクト配列

オブジェクトも配列化できる。

  1. String[] myString;

 
UI も配列化可能。

  1. Button[] myButton;

あ、これは Android の話かな。
Java 本家はいじってないのでわからない。
 

インスタンスの生成(領域確保)

Java で配列を利用する場合は、インスタンスの生成と同時に領域を確保 しなければならない。
つまり 利用前 に領域を確保しなければならない。

  1. // まず宣言し
  2. int[] myInt;
  3. // インスタンスの生成と同時に領域を確保(利用前に領域確保)
  4. myInt = new int[3];
  5. // 利用
  6. myInt[0] = 2011;
  7.  
  8. // 宣言と同時にインスタンスの生成
  9. int myInt = new int[3];

int[3] の 3 は、3箇所確保 という意味なので
上記の例の場合は

  • myInt[0]
  • myInt[1]
  • myInt[2]

の領域を確保したことになる。
 

初期化
  1. int[] myInt;
  2. myInt = new int[] {1, 2, 3};
  3. myInt = {1, 2, 3}; // new int[] は省略可能
  4. String[] myString;
  5. myString = new String[] {"A", "B", "C"};
  6. myString = {"A", "B", "C"}; // new String[] は省略可能
  7.  
  8. // 宣言と同時に初期化も可能
  9. int[] myInt = new int[] {1, 2, 3};
  10. int[] myInt = {1, 2, 3}; // new int[] は省略可能
  11. String[] myString = new String[] {"A", "B", "C"};
  12. String[] myString = {"A", "B", "C"}; // new String[] は省略可能

こんな感じ。

{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で作成する多次元配列操作ライブラリ
 

多次元配列
  1. int[][] myInt = new int[3][2];

このようにすると、以下のような6つの領域が確保される。

  • myInt[0][0]
  • myInt[0][1]
  • myInt[1][0]
  • myInt[1][1]
  • myInt[2][0]
  • myInt[2][1]

 

  1. int[] myInt = new int[3];
  2. int[] myInt[0] = new int[2];
  3. int[] myInt[1] = new int[1];
  4. int[] myInt[2] = new int[3];

このようにすると、同じ多次元配列でも
2階層目の要素数が異なる多次元配列を生成できる。

と思ったら、こんなエラーが出た。

トークン “0” に構文エラーがあります。このトークンを削除してください Java 問題
型の不一致: int[] から int[][] には変換できません Java 問題
重複ローカル変数 myInt Java 問題

できないのかぁ。
 
正しい書式はこちら。

  1. int[][] myInt = new int[3][];
  2. myInt[0] = new int[2];
  3. myInt[1] = new int[1];
  4. myInt[2] = new int[3];
  • 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 ステートメント

配列(とコレクション)に特化した for ステートメント がある。

  1. // 配列の生成
  2. int[] myInt = {1, 2, 3};
  3.  
  4. // for (要素を受け取る変数: 配列)
  5. for (int i: myInt) {
  6.     System.out.println(i);
  7. }

5行目 ( ) 内は、: (コロン)であって ; (セミコロン)ではない。
 

length

length プロパティは、配列の要素数を返す。

  1. int[] myOdd = {1, 3, 5};
  2. System.out.printIn(myOdd.length);
  3.  
  4. // output
  5. // 3

 

ダンプ

配列の中身を見るには

  • 1次元配列 ・・・ Arrays.toString メソッド
  • 多次元配列 ・・・ Arrays.deepToString メソッド

 

  1. // 1次元配列
  2. int[] intArray = {1, 2, 3, 4, 5};
  3. Log.i("Dump", Arrays.toString(intArray) );
  4. // [1, 2, 3, 4, 5]
  5.  
  6. // 3次元配列
  7. int[][][] intMultidimensionalArray = { { {1, 2, 3, 4, 5}, {6, 7, 8} }, { {11, 21, 31}, {41, 51, 61, 71, 81} } };
  8. Log.i("Dump", Arrays.deepToString(intMultidimensionalArray) );
  9.  
  10. // [[[1, 2, 3, 4, 5], [6, 7, 8]], [[11, 21, 31], [41, 51, 61, 71, 81]]]

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 がセットされる

 

代入演算子
  1. int[] myOdd = {1, 3, 5, 7, 9, 11};
  2. int[] myOdd2 = myOdd;

わかりやすいw
 

for ステートメント
  1. int[] myOdd = {1, 3, 5, 7, 9, 11};
  2. int[] myOdd2 = new int[myOdd.length];
  3.  
  4. for (int i = 0; i < myOdd.length; i++) {
  5.     myOdd2[i] = myOdd[i];
  6. }[/java2se6]
  7.  
  8. <div class="flow2">clone メソッド</div>
  9. [java2se6]int[] myOdd = {1, 3, 5, 7, 9, 11};
  10. int[] myOdd2 = (int[]) myOdd.clone();

protected Object clone()

JDK 6 ドキュメント:Object clone

これは単純で素敵。
 

arraycopy メソッド
  1. int[] myOdd = {1, 3, 5, 7, 9, 11};
  2. int[] myOdd2 = new int[5];
  3.  
  4. System.arraycopy(myOdd, 1, myOdd2, 3, 2);

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 クラスで認識するため、データ型があいまいになる。
(このようにクラスを親クラスとして捉えることを ダウンキャスト というらしい)
 

copyOf メソッド
  1. int[] myOdd = {1, 3, 5, 7, 9, 11};
  2. int[] myOdd2 = Arrays.copyOf(myOdd, myOdd.length);

public static int[] copyOf(int[] original, int newLength)
各データ型毎に定義されている。

JDK 6 ドキュメント:Arrays copyOf

第1引数:コピー元配列
第2引数:コピー元から取り出す要素数(キー 0 からいくつ分か)
 

copyOfRange メソッド
  1. int[] myOdd = {1, 3, 5, 7, 9, 11};
  2. int[] myOdd2 = Arrays.copyOfRange(myOdd, 1, 4);

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 相当のため実験できず。
コピー方式についても不明。

またそのうち実験してみよう。

Posted by muchag | Java |
初回投稿:2011-04-19 (火) 12:40:34 | 最終更新:2011-04-20 (水) 18:21:45

コメントはまだありません »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment