Javaでの配列の使い方

イントロダクション

配列は、複数の要素をグループ化して保存することができます。配列を使えば、参照型やプリミティブ型を含むどんな種類のデータでも保存することができます。ただし、すべての配列要素は同じデータ型でなければなりません。配列のデータ型は配列が作成された時に指定され、変更することはできません。同様に、配列の長さ、つまりいくつの要素を格納できるかは最初に定義され、変更することはできません。

配列はJavaにおいて基本的な役割を果たし、多くのコアデータ型がそれに基づいています。例えば、よく使われる参照型のStringは実際にはchar要素の配列として実装されています。ですので、あなたがそれについて知らなくても、すでに配列を使ったことがあるということです。

このチュートリアルでは、パスワードを安全に保存するためにchar配列を使用します。これは、配列の一般的な使用例です。パスワードを保存するために、Stringではなくchar配列を使用するのは、Stringオブジェクトが不変であるためです。つまり、上書きすることができません。したがって、もはやパスワードのStringオブジェクトが必要なくなったとしても、ただ破棄することはできません。これは、オブジェクトがメモリ内に残るため、攻撃者が理論的にこのメモリの一部にアクセスし、パスワードを読む可能性があることを意味します。対照的に、char配列として保存されたパスワードを簡単に上書きし、使用不可にすることができます。このため、メモリを検査してパスワードを取得する可能性はありません。

前提条件 (Zenteijōken)

このチュートリアルに従うには、以下が必要です:

  • An environment in which you can execute Java programs to follow along with the examples. To set this up on your local machine, you will need the following:
  • Java (version 11 or above) installed on your machine, with the compiler provided by the Java Development Kit (JDK). For Ubuntu and Debian, follow the steps for Option 1 in our tutorial How To Install Java with Apt on Ubuntu 22.04. For other operating systems, including Mac and Windows, follow the download options for Java installation.
  • To compile and run the code examples, this tutorial uses Java Shell, which is a Read-Evaluate-Print Loop (REPL) run from the command line. To get started with JShell, check out the Introduction to JShell guide. To avoid redundant instructions, all examples are executed in one JShell session and use the same variables.
  • Familiarity with Java and object-oriented programming, which you can find in our tutorial How To Write Your First Program in Java.
  • An understanding of Java data types, which is discussed in our tutorial Understanding Data Types in Java.

配列の作成

配列を使い始めるには、まず配列を作成する必要があります。配列を作成する方法はいくつかあり、配列が保持する要素を事前に知っているかどうかによって作成方法が異なります。

Info

情報:このチュートリアルでの例のコードに従うためには、jshellコマンドを実行してローカルシステムでJavaシェルツールを開いてください。その後、jshell>プロンプトの後にコピー、貼り付け、または例を編集することができます。jshellを終了するには、/exitと入力してください。

配列の要素が分からない場合、空の配列を作成してサイズを定義することができます。以下のようにしてください。

  1. char[] password = new char[6];

 

charキーワードの後に続く組み合わせ[]は、変数passwordを配列として定義します。charキーワードは、変数がcharの基本データ型を保持することを意味します。配列オブジェクトを作成するためには、char[6]という形で配列を定義したnewキーワードを使用します。これにより、charの基本データ型を含んでおり、6つの要素を保持する配列が作成されます。

前のコードを実行すると、以下の出力が表示されます。

  1. password ==> char[6] { ‘\000’, ‘\000’, ‘\000’, ‘\000’, ‘\000’, ‘\000’ }

 

出力は、新しいchar配列がパスワードという名前で作成されたことを確認します。これは現在、6つの要素([6])を格納でき、それらは空です(\000)。

もしくは、既に配列要素を知っている場合は、このようにchar要素を持つ配列を作成することもできます。その配列をパスワードと呼びます。

  1. char[] password = new char[] {‘s’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’};

 

`イコール`の前にある文の左側は、最初の空の配列の例と同じく、`password`という名前のchar配列が定義されています。文の後ろの2番目の部分は、再び`new`キーワードで始まりますが、要素の数は明示的に与えられていません。代わりに、すべての6つの要素がリストされています。リストは開きかっこから始まり、6つの要素が続きます。要素はcharのプリミティブ型なので、シングルクォーテーション(’)で囲まれています。リストは閉じかっこで終わります。

前のコードをjshellに貼り付けると、次のような出力が得られます。

Output

password ==> char[6] { ‘s’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’ }

出力は、パスワードの文字配列が作成され、その要素がリスト化されていることを確認します。

後者の例では、配列を作成する際に要素を指定しました。これにより、要素に値を割り当てるための追加の命令を書く必要がなくなりました。これが、この方法で配列を作成する利点です。また、要素を個別に定義した各要素で配列を埋めるためのコードを作成することもできます。次にこれを行います。

配列要素の指定と変更

配列の要素を常に把握することはできませんので、配列を作成する際にそれらを指定することができない場合もあります。しかし、配列の要素を最初に指定したかどうかにかかわらず、後からいつでも指定または変更することができます。

例えば、パスワードの配列の要素を変更する場合、その要素のインデックス、つまり配列内の場所を参照して次のようにすることができます。

  1. password[0] = ‘n’;

 

password[0]を使用すると、password配列の最初の要素を指すことになります。配列の要素は0から番号がつけられているため、最初の要素のインデックスは0になります(この場合も同様です)。配列の要素のインデックス番号は常に角括弧([])の間に指定されます。配列の要素を再定義し、新しい値(’n’というcharプリミティブ)を割り当てます。

jshellで前述のステートメントを実行すると、以下のような出力が得られます。

Output

$8 ==> ‘n’

jshell内では、一時変数$8が使用されていますが、あなたの場合には異なる数値かもしれません。

jshellには、パスワードの配列が意図したように変更されたかを確認するために使用できるユニークな機能があります。例えば、パスワードという配列の名前をjshellに貼り付けると、追加のメソッドなしで配列とその要素が表示されます。

  1. password

 

ジェシェルでは、次のような出力が得られます。

Output

password ==> char[6] { ‘n’, ‘e’, ‘c’, ‘r’, ‘e’, ‘t’ }

この出力は、配列のパスワードを s, e, c, r, e, t から n, e, c, r, e, t に正常に変更したことを確認しています。今後、もし攻撃者がサーバーにアクセスした場合、元のパスワードではなく変更後のパスワードを取得することになります。また、もしパスワードをString変数に保存している場合、新しい値を再代入しても古い値のオブジェクトは一定時間メモリ上に残り、攻撃者がそれを読む可能性があります。

このチュートリアルの間、パスワードの配列は引き続き使用しますので、一貫性を保つために、再度参照してコマンドを実行することで、最初の要素の値をsに戻してください。

  1. password[0] = ‘s’;

 

これにより、一時的な変数を使用した前回と似たような出力が得られ、$25の場合は変更が成功したことが確認されます。

Output

$25 ==> ‘s’

もう一度、元のパスワードの配列を持っています。要素は ‘s’、’e’、’c’、’r’、’e’、’t’です。配列の要素の作成と変更方法を知ったので、要素を読み取って使用する時が来ました。

要素を取得する。

特定の配列要素を取得する際には、そのインデックスで操作します。例えば、パスワード配列の2番目の要素を取得するためには、次のコードを使用できます。

  1. System.out.println(password[1]);

 

このコードでは、println()メソッドを使用して、パスワード配列の2番目の要素を出力します。(System.out.printlnステートメントの詳細については、当社のJavaで最初のプログラムを書くチュートリアルをご覧ください。)配列の要素は0から始まるため、2番目の要素はインデックス1を持ちます。

このコードを実行すると、次のような結果が得られます。

Output

e

出力は、2番目の配列要素eを表示します。その要素を表示するだけでなく、char値が適している他の方法でも使用することができます。

さらに、Javaのループの使用方法について解説した当社のチュートリアル「How To Use Loops in Java」に従い、foreachループを使うことで配列の要素すべてに繰り返し処理が可能です。ループは、反復的なプログラムの流れを制御するための構造であり、foreachループは特に配列を繰り返し処理する際に、最小限の雛形コードが必要で非常に便利です。以下に例を示します。

  1. for (char c : password) {
  2. System.out.print(c);
  3. }

 

このforeachループはパスワードの配列を反復処理し、一時的なchar変数であるcを使用します。各反復では、cはパスワード配列の最初から最後の要素まで移動します。cが配列要素の値を取得すると、コードのブロック内でcを適切に使用することができます。前の例では、print()メソッドでcを出力します。

print()メソッドは改行なしで引数を出力することに注意してください。一方、これまでのチュートリアルでは、println()メソッドを使用しており、実行時には改行が行われます。この場合、password配列の要素をすべて同じ行に出力するためには、print()メソッドがより適しており、結果は単語としてより良く視覚化されます(「secret」)。

もし前述の手順を正確に守り、このコードをjshellで実行すれば、以下の出力結果が得られます。

Output

secret

最初の配列要素をnからsにリセットするステップを逃すと、代わりにnecretを取得します。

あなたがこれまでに築いてきた知識を組み合わせると、配列の要素をすべて取得することができます。これ以降は、配列についてさらに深く掘り下げ、さまざまな機能を実行するための便利な配列メソッドを学ぶ準備が整っています。

配列のメソッドを使用する

Javaには、java.utilパッケージにある非常に便利なArraysクラスがあります。このクラスは、配列を扱う際に便利なメソッドを提供することで、一般的な使用ケースに役立ちます。つまり、車輪の再発明をしなくても、重複した努力を省くことができます。以下に、最も頻繁に使用されるメソッドのいくつかを示します。

equals()メソッド

equals()メソッドは、2つの配列が等しいかどうかを比較します。2つの配列が等しいためには、同じ長さ、要素、順序を持っている必要があります。パスワード配列の例で続けると、n、o、n、eという文字を含むpassword2という2番目の配列を作成します。

  1. char[] password2 = new char[] {‘n’, ‘o’, ‘n’, ‘e’};

 

jshellでこのコードを実行すると、以下の確認が表示されます。

Output

password2 ==> char[4] { ‘n’, ‘o’, ‘n’, ‘e’ }

以下の出力は、password2配列を持っていることを確認します。それは4つの要素を持ち、それらも出力されます。以前のjshellセッションを終了していない場合、元のpassword配列も持っています。jshellセッションを終了している場合は、password配列を再作成するためのCreating Arraysの手順を使用する必要があります。これにより、比較できる2つの配列が得られます。

今、このように2つの配列を比較することができます。

  1. System.out.println(Arrays.equals(password, password2));

 

前の行では、passwordとpassword2の配列を比較するArray.equal()メソッドの結果をprintln()メソッドを使用して出力しています。

2つの配列が異なるので、結果はfalseになります。

Output

false

上記の出力の「false」は、二つの配列が等しくないことを示しています。練習として、他の配列を作成して比較してみてください。もし二つの配列が等しい場合は、「true」の結果が得られます。

ソート()メソッド

sort()メソッドを使用すると、配列の要素を昇順に並べ替えることができます。このメソッドを使うと、パスワード配列の文字をアルファベット順に並べ替えることができます。以下のように実行します。

  1. Arrays.sort(password);

 

その後、その配列の名前をjshellで発行することで、変更されたことを確認するために再度配列を印刷することができます。

  1. password;

 

jshellの出力は次のようになります。

Output

password ==> char[6] { ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’ }

これにより、配列はまだ同じ要素を持っていることが確認されましたが、その順序が変わりました。配列の要素は、’s’、’e’、’c’、’r’、’e’、’t’から’c’、’e’、’e’、’r’、’s’、’t’に並び替えられました。このように配列の順序を変更することは、元の順序が重要な場合には良い考えかもしれません。パスワードの場合と同様に、順序を変更すると、パスワードは元のものと異なり、機能しません。ただし、他の用途では、配列要素の順序が重要ではない場合もありますし、初期の並べ替えが必要な場合があります。これについては次に説明します。

バイナリサーチ()メソッド

binarySearch()メソッドは、指定された値を持つ配列の要素を検索します。このメソッドの特異性の一つは、最初に配列の要素がソートされている必要があることです。そうでない場合、予期しない結果が返されます。したがって、パスワードの配列をソートした後、要素のインデックスを見つけることができます。たとえば、パスワードの中で文字cのインデックスを見つけて、それを表示することができます。

  1. System.out.println(Arrays.binarySearch(password, ‘c’));

 

これによって生じるものがあります。

Output

0

パスワードの配列がソートされ、以下のようになっていることを思い出してください: ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’。数字0が表示されているため、文字’c’はインデックス0を持っていることを意味します。なぜなら、これは配列の最初の要素だからです。

「copyOf()」メソッド

copyOf()メソッドは、配列のサイズを増減する必要がある場合に、指定された配列を新しい配列にコピーします。配列の長さは作成後に変更できないため、このメソッドを使用して旧配列からコピーされた内容を含む必要なサイズの新しい配列を作成できます。

たとえば、パスワードの配列は現代のセキュリティ要件には適さないため、只今、6つの要素しか保存できません。そのサイズを増やすためには、次のようにcopyOf()を使用して新しい大きな配列を作成することができます。

  1. password = Arrays.copyOf(password, 10);

 

前の例では、パスワードの値を新しい配列に再割り当てしています。この新しい配列は、古いパスワード配列を要素数10の新しい配列にコピーした結果です。コピーするために、Arrays.copyOf()メソッドを使用しました。このメソッドは、2つの引数を受け取ります。最初の引数はコピー元の配列です。2番目の引数は作成する新しい配列の長さです。

前述のコードをjshellで実行すると、次のような出力が得られます。

Output

password ==> char[10] { ‘c’, ‘e’, ‘e’, ‘r’, ‘s’, ‘t’, ‘\000’, ‘\000’, ‘\000’, ‘\000’ }

前の行は、パスワード配列が現在10つの要素を持っていることを示しています。最初の6つの要素は、アルファベット順に並べ替えられた元のパスワード配列から来ており、’c’、’e’、’e’、’r’、’s’、’t’となりました。最後の4つの値は空です。なぜなら、Arrays.copyOf()は要素数を増やす際に新しい要素を空で埋めるためです。

普通の方法で、配列オブジェクトが持つ長さのプロパティを確認することで、新しい配列が10の要素を持つことも確認できます。この値は通常の方法で出力することができます。

  1. System.out.println(password.length);

 

ここでは、println() メソッドを使用し、password.length を引数として渡します。jshell からの出力は次のようになります。

Output

10

このセクションで取り上げられたメソッドは、配列に関連するものの中でも非常に有用なものです。公式のArraysのドキュメントを参考にして、さまざまなメソッドを自分自身で探索することができます。

結論

このチュートリアルでは、関連するアイテムをグループ化するためにJavaの配列を使用しました。配列の作成方法、表示方法、およびその内容を使用する方法について学びました。また、配列を扱うためのベストプラクティスと便利なメソッドも学びました。

Javaについては、弊社のJavaでのコーディングシリーズをチェックしてください。

コメントを残す 0

Your email address will not be published. Required fields are marked *