Javaの多次元配列を完全攻略!初心者でも2次元配列がわかる基礎から応用
生徒
「Javaで表形式のようなデータを扱いたいのですが、普通の配列だと管理が大変で……。何か良い方法はありますか?」
先生
「そんな時は『多次元配列』を使うのが最適です。配列の中にさらに配列を入れることで、縦と横の広がりを持つデータを効率よく扱えるようになりますよ。」
生徒
「配列の中に配列……? 少し難しそうですが、初心者でも書けるようになりますか?」
先生
「大丈夫です!まずはイメージを掴むところから、具体的な書き方まで順番に解説していきますね。」
1. 多次元配列とは何か?
Javaのプログラミングにおいて、通常の「配列」は一列に並んだデータの集合体です。これを「1次元配列」と呼びます。しかし、現実世界のデータには、出席簿や成績表、地図の座標、カレンダーのように「縦と横」の要素を持つものが多く存在します。これらを表現するために使われるのが多次元配列です。
最もよく使われるのは、縦と横の2つの軸を持つ「2次元配列」です。2次元配列は、イメージとしては「Excelのワークシート」や「数学の行列」に非常に近いです。複数の行があり、それぞれの行に複数の列(データ)が存在する構造をしています。Javaでは、配列の要素として別の配列を格納することで、この多重構造を実現しています。難しく聞こえるかもしれませんが、1次元配列の知識があれば、その積み重ねで理解することができます。
2. 2次元配列の宣言と初期化の基本
Javaで2次元配列を扱う際、まずは「どんな型のデータを、どれくらいの数入れるか」をコンピュータに伝える必要があります。これが「宣言」と「生成」のステップです。基本的な構文は以下の通りです。
型[][] 配列名 = new 型[行数][列数];
例えば、3行4列の整数型(int)の配列を作りたい場合は、int[][] table = new int[3][4];と記述します。ここで重要なのは、カギ括弧[]が2つ重なっている点です。これが「配列の配列」であることを示しています。最初の数字が行(縦)の数を表し、二番目の数字が列(横)の数を表します。この宣言を行うと、メモリ上には指定されたサイズの領域が確保され、数値型の場合は初期値として「0」が自動的に代入されます。
また、最初から中身が決まっている場合は、中括弧{}を使って一気に初期化することも可能です。この方法を「配列リテラルによる初期化」と呼びます。
public class ArraySample1 {
public static void main(String[] args) {
// 2行3列の配列を宣言して値を代入するパターン
int[][] scores = new int[2][3];
scores[0][0] = 80;
scores[0][1] = 90;
scores[0][2] = 70;
scores[1][0] = 55;
scores[1][1] = 60;
scores[1][2] = 40;
// 初期化と同時に値を設定するパターン
int[][] sales = {
{100, 200, 300},
{400, 500, 600}
};
System.out.println("scoresの最初の値: " + scores[0][0]);
System.out.println("salesの最後の値: " + sales[1][2]);
}
}
scoresの最初の値: 80
salesの最後の値: 600
3. インデックスの数え方とデータの取り出し
多次元配列からデータを取り出したり、値を書き換えたりする場合も、1次元配列と同様に「インデックス(添字)」を使用します。ただし、2次元配列では「行番号」と「列番号」の2つを指定する必要があります。ここで注意しなければならないのは、Javaのインデックスは必ず0から始まるというルールです。
例えば、data[1][2]と書いた場合、それは「2行目の3列目」の要素を指します。日常生活の感覚で「1行目の2番目」と考えてしまうと、プログラムが正しく動作しなかったり、存在しない場所を指してエラー(ArrayIndexOutOfBoundsException)が発生したりする原因になります。配列の操作に慣れるまでは、頭の中で「行マイナス1、列マイナス1」と念じながらコードを書くのがコツです。
また、多次元配列は「配列の配列」であるため、配列名[行番号]までを指定すると、その行全体(1次元配列としての要素)を指すことになります。これは少し高度な使い方ですが、行単位でデータを処理する際に非常に役立つ知識です。
4. for文を使った多次元配列のループ処理
多次元配列の真価を発揮させるのが、繰り返し処理(for文)との組み合わせです。1次元配列では1つのfor文で済みましたが、2次元配列では「外側のループで行を回し、内側のループで列を回す」という二重ループの構造をとります。これにより、表形式のデータを一括で画面に表示したり、合計値を計算したりすることが可能になります。
ループの終了条件には、配列名.lengthプロパティを使用するのが一般的です。2次元配列において、配列名.lengthはその配列の「行数」を返し、配列名[行インデックス].lengthはその行の「列数」を返します。この仕組みを理解しておけば、たとえ行ごとに列の長さが異なるような特殊な配列であっても、柔軟に処理することができます。
public class ArrayLoopSample {
public static void main(String[] args) {
// 成績データの多次元配列(3人分の3科目)
int[][] reportCard = {
{85, 78, 92},
{60, 55, 70},
{100, 95, 98}
};
System.out.println("--- 成績一覧表 ---");
for (int i = 0; i < reportCard.length; i++) {
System.out.print((i + 1) + "人目: ");
for (int j = 0; j < reportCard[i].length; j++) {
System.out.print(reportCard[i][j] + " ");
}
System.out.println(); // 改行
}
}
}
--- 成績一覧表 ---
1人目: 85 78 92
2人目: 60 55 70
3人目: 100 95 98
5. 拡張for文を使ったスマートな書き方
Java 5から導入された「拡張for文」を使うと、インデックスを意識することなく多次元配列の要素をスキャンできます。通常のfor文よりも記述がシンプルになり、読み間違いを防げるというメリットがあります。初心者の方には特におすすめしたい書き方です。
2次元配列に拡張for文を適用する場合、外側のループでは「行」を一つの配列として取り出し、内側のループでその配列の中身を一つずつ取り出します。コードの可読性が格段に上がり、バグが入り込む余地を減らすことができます。ただし、拡張for文は「要素の参照」には向いていますが、「特定のインデックスの値を書き換える」用途には適していないため、目的に応じて使い分けることが大切です。
public class EnhancedForSample {
public static void main(String[] args) {
String[][] seatingChart = {
{"田中", "佐藤", "鈴木"},
{"高橋", "伊藤", "渡辺"}
};
System.out.println("座席表の確認を始めます。");
for (String[] row : seatingChart) {
for (String name : row) {
System.out.println("出席者: " + name);
}
}
}
}
座席表の確認を始めます。
出席者: 田中
出席者: 佐藤
出席者: 鈴木
出席者: 高橋
出席者: 伊藤
出席者: 渡辺
6. ジャグ配列(不規則な多次元配列)の解説
Javaの多次元配列の面白い特徴として、「各行の長さがバラバラでも良い」という点があります。これを一般的に「ジャグ配列(Jagged Array)」と呼びます。「ジャグ」とは「ギザギザした」という意味です。例えば、1組は3人、2組は5人、3組は2人のように、グループごとにデータ数が異なる場合に非常に効率的です。
ジャグ配列を作るには、まず行数だけを指定して宣言し、その後各行に対して個別に配列を生成・代入します。int[][] jagged = new int[3][];のように二番目の括弧を空にしておくのがポイントです。メモリの節約にも繋がりますし、より現実に即した柔軟なデータ構造を構築できるようになります。この概念をマスターすれば、Javaの配列操作における中級者への第一歩を踏み出したと言えるでしょう。
public class JaggedArraySample {
public static void main(String[] args) {
// 各行で列数が異なるジャグ配列の作成
int[][] myJaggedArray = new int[3][];
myJaggedArray[0] = new int[2]; // 0行目は2列
myJaggedArray[1] = new int[4]; // 1行目は4列
myJaggedArray[2] = new int[1]; // 2行目は1列
// 値を代入して確認
myJaggedArray[1][3] = 999;
for (int i = 0; i < myJaggedArray.length; i++) {
System.out.println(i + "行目の長さは: " + myJaggedArray[i].length);
}
System.out.println("myJaggedArray[1][3]の値: " + myJaggedArray[1][3]);
}
}
0行目の長さは: 2
1行目の長さは: 4
2行目の長さは: 1
myJaggedArray[1][3]の値: 999
7. 多次元配列を活用する際の注意点とコツ
多次元配列を扱う上で最も注意すべきは、やはり「メモリ管理」と「パフォーマンス」です。3次元、4次元と次元を増やしていくことは技術的に可能ですが、人間がその構造を理解するのが難しくなり、プログラムの保守性が著しく低下します。基本的には2次元、どうしても必要な場合でも3次元までにとどめておくのが開発現場のベストプラクティスです。
また、大量のデータを扱う場合、配列よりも「ArrayList」などのコレクションクラスを使用する方が便利な場面も多いです。しかし、ゲーム開発のマップデータや画像のピクセル解析、数学的な計算処理などでは、固定長の多次元配列が今でも現役で活躍しています。状況に応じて、配列のシンプルさとコレクションの便利さを使い分けられるようになりましょう。最後に、多次元配列を扱うときは、常に「今、自分はどの行のどの列を操作しているのか」をコメントや変数名(i, j ではなく row, col など)で工夫して可読性を高める努力を忘れないでください。