004-006-008

配列変数の参照を理解する

初級

問題説明

配列参照の代入:共有状態の理解

Javaの配列は値型ではなく参照型です。この基本概念が、配列を別の変数に代入すると独立したコピーではなく共有状態が作られる理由を説明しています。

参照の概念は最初は難しく感じるかもしれませんが、一緒に理解していきましょう。

学習目標

  • 配列変数への参照代入の動作を実装で確認できる
  • 参照代入により同一配列を指す複数変数の関係を適用できる
  • 参照型変数と基本型変数の代入の違いを説明できる

学習ポイント

  • 参照と値: 配列変数はデータではなくメモリアドレスを保持
  • 共有状態: 2つの変数が同じ配列を指すことができる
  • 副作用: 一方の変数経由の変更は全参照に影響
  • 防御的コピー: 独立性にはclone()やArrays.copyOf()を使用

参照コピーの動作

int[] numbers1 = {10, 20, 30};
int[] numbers2 = numbers1;  // 参照のコピー、配列のコピーではない

numbers2[0] = 100;
System.out.println(numbers1[0]); // 100を出力(同じ配列!)

プリミティブ型と参照型

プリミティブ(int)参照(int[])
int a = 10;
int b = a; // 値のコピー
b = 20;
// aは依然10
int[] a = {10};
int[] b = a; // 参照のコピー
b[0] = 20;
// a[0]も20になる

よくある間違い

参照とコピーの違いでつまずいても心配ありません。もう一度コードを見直して、それぞれの動作を確認してみましょう。

間違い1: 独立したコピーを期待

問題のあるコード:

int[] original = {1, 2, 3};
int[] backup = original;  // バックアップではない!
original[0] = 999;
// backup[0]も999 - データ「消失」

正しいコード:

int[] original = {1, 2, 3};
int[] backup = original.clone();  // 真のコピー
original[0] = 999;
// backup[0]は依然1

間違い2: 意図しないメソッドの副作用

問題のあるコード:

void sortArray(int[] arr) {
    Arrays.sort(arr);  // 呼び出し元の配列を変更!
}

防御的なコード:

void sortArray(int[] arr) {
    int[] copy = arr.clone();
    Arrays.sort(copy);  // オリジナルは変更されない
}

真のコピーを作成する方法

// 方法1: clone()
int[] copy1 = original.clone();

// 方法2: Arrays.copyOf()
int[] copy2 = Arrays.copyOf(original, original.length);

// 方法3: System.arraycopy()
int[] copy3 = new int[original.length];
System.arraycopy(original, 0, copy3, 0, original.length);

実務での活用

  • 防御的プログラミング: 信頼できないソースからの配列をクローン
  • イミュータブルクラス: 内部配列ではなくコピーを返す
  • メソッドパラメータ: 配列が変更されるかドキュメント化

補足: オブジェクト配列の場合、clone()は浅いコピーを作成します。配列は新しいですが、要素は依然として参照を共有しています。

前提知識の詳細説明

この問題を解くために必要な知識を確認しましょう。

基本概念

この問題で扱うプログラミングの基本概念を理解することが、正しい解答への第一歩です。コードの各要素がどのように連携して動作するかを把握しましょう。

実装アプローチ

問題を解くための考え方を段階的に整理します:

  1. 問題文を読み、入力と出力の関係を理解する
  2. 必要な変数やデータ構造を特定する
  3. 処理の流れを組み立てる
  4. テストケースで動作を確認する

コードを実行してみませんか?

この問題のコードエディタと実行機能を使用するには、ログインしてください。

アカウントをお持ちでない方