問題1-22
String型の変数inputPasswordが宣言してあります。
System.console().readLIne() の記述は、キーボードから文字列の入力を受け付けるもので、その値で変数inputPasswordを初期化しています。
StringImportantPracticeクラスには、正しいパスワードを表現するString型の定数PASSWORDが定義してあります。
キーボードから入力したパスワードの値がパスワード定数の値と等しい場合は「パスワードが一致しました」と表示し、パスワード定数の値と等しくない場合は「パスワードが一致しません」と表示してください。
【実行結果】
パスワードを入力してください ABC パスワードが一致しません
パスワードを入力してください XYZ パスワードが一致しました
【StringImportantPractice.java】
public class StringImportantPractice { // 正しいパスワード定数 private static final String PASSWORD = "XYZ"; public static void main(String[] args) { System.out.println("パスワードを入力してください"); // 入力パスワード変数の宣言と初期化 String inputPassword = System.console().readLine(); // ここからパスワードの一致を調べてください } }
解答例
【StringImportantPractice.java】
public class StringImportantPractice { // 正しいパスワード定数 private static final String PASSWORD = "XYZ"; public static void main(String[] args) { System.out.println("パスワードを入力してください"); // 入力パスワード変数の宣言と初期化 String inputPassword = System.console().readLine(); // パスワードの一致を調べる(等値のチェック) if(PASSWORD.equals(inputPassword)) { System.out.println("パスワードが一致しました"); } else { System.out.println("パスワードが一致しません"); } } }
Eclipseで動作させた場合、System.console()の返却値がnullになり動作せず、Null Pointer Exceptionが発生してしまうので、下記のようにする必要があります。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class StringImportantPractice { // 正しいパスワード定数 private static final String PASSWORD = "XYZ"; public static void main(String[] args) throws IOException { System.out.println("パスワードを入力してください"); // 入力パスワード変数の宣言と初期化 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String inputPassword = br.readLine(); // パスワードの一致を調べる(等値のチェック) if(PASSWORD.equals(inputPassword)) { System.out.println("パスワードが一致しました"); } else { System.out.println("パスワードが一致しません"); } } }
解説
今回の問題は、難易度は高くないのですが、かなり重要な問題です。
もしかしたら、何度キーボードから「XYZ」と入力しても、「パスワードが一致しません」と出力されてしまう・・・・。
となってギブアップしてしまった人もいるかもしれません。
うまく動かない人は、パスワード認証部分を次のように記述していませんか?
if(PASSWORD == inputPassword) { System.out.println("パスワードが一致しました"); }
一見あっているように見えますが、Javaでは大間違いです。
Javaのデータタイプには大きく分けて基本データ型と参照型があります。
次のプログラムを見てください。
String str = "ABC";
このString型変数strには、「ABC」という値が入っていると思っている人はいませんか?
Javaで文字列はとてもよく利用されるので、あたかも基本データ型のように簡単に扱えるように工夫されています。
それでも、String型変数strに格納されている本当の値は「ABC」ではないんです。
String型はあくまで参照型です。
String型変数strの中にはString型オブジェクトがどこにあるのか、「居場所」が格納されているのです。
詳細については下記を参照してみてください。
パスワード認証の話に戻りますが、うまく動作しない例では、2つの文字列型変数を「==」演算子で比較しました。
これは同じ「居場所」かどうかを調べることになります。
たとえ2つの文字列型変数が「ABC」を指していても、「居場所」が異なれば「==」で比較しても絶対にtrueにはならないのです。
たとえ同姓同名の人が2人いても、それは名前が同じであって同一人物という解釈にはならないのと同じです。
もちろん文字列の等値チェックを行う正しいやり方がJavaにはあります。
Javaでは文字列はStringクラスのオブジェクトですから、インスタンスメソッドを呼び出すことができます。
Stringオブジェクトが等値であるかどうかを調べるのは「equals」メソッドを使用すれば解決します。
ポイント!「同一」と「等値」
「居場所」が同じであることを「同一」、オブジェクトが持つデータが同じであることを「等値」と言います。
すべてのクラスはObjectクラスを継承していますが、実はequalsメソッドはObjectクラスで定義されているメソッドです。
だからといってすべてのオブジェクトはequalsメソッドで等値チェックができるわけではなく、Objectクラスが本来持っているequalsメソッドは、結局ただの同一チェックを行っています。
等値チェックが必要なクラスは、何をもって等値と判断するかを考慮し、equalsメソッドをオーバーライドして機能改良を図っています。
つまり、Stringクラスはequalsメソッドをオーバーライドして機能を改良しているのです。
最後にまとめです。
「文字列の等値チェックは必ずequalsメソッドでチェック!」
もし開発現場で文字列の等値チェックを「==」で行っているプログラムを見つけたならば、それはほぼ100%バグです。
すぐにそのコーディングを行ったプログラマに報告してあげましょう。
参考図書
LINE公式アカウント
仕事が辛くてたまらない人生が、仕事が楽しくてたまらない人生に変わります。
【登録いただいた人全員に、無料キャリア相談プレゼント中!】