これまで文字列を使用してきました。それは二重引用符で囲われたもので、例えば"こんにちは。"
というのが文字列でした。そして、System.out.printlnメソッド(正確には、Systemクラスに所属する staticな参照型のフィールドである outの参照先のインスタンスのインスタンスメソッド println)などを使用して文字列を画面に表示したりしていました。具体的には以下の感じです。
System.out.println("こんにちは。");
Javaでは、文字列は String型のインスタンスとして扱われます。インスタンスを作る場合、通常は予約語new
を必要とします。しかし、String型の場合には、二重引用符で囲うだけで、事実上、String型インスタンスが生成されている点に注意してください(詳細な動きを説明することはとても難しいため、省略します)。
ともかく、文字列とは String型のインスタンスです。ということは String型の変数を使って参照することができます。まずは、その例を挙げてみたいと思います。
ソースコードは以下の通り。
I101/I101.java
/** * String型変数を使用します。 */ public class I101 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { // 文字列を参照型へ紐づける String s = "こんにちは。"; String t = "さようなら。"; // 文字列を表示する System.out.println(s); System.out.println(t); } }
実行結果は以下の通り。
こんにちは。 さようなら。
このプログラムを実行する中で、2個の String型インスタンスが生成されることを理解してください。
イメージとしては以下のような感じです。
「文字列は変更できない」と表現するよりも、「String型インスタンスの内容は変更できない」と言ったほうが適切かな。String型インスタンスは、一度生成したが最後、その内容を変更することは永遠にできない、という特殊な性質があります。
とりあえず覚えてください。実例は、この後で、幾つか見ていきます。
文字列と文字列を連結する際には、文字列連結演算子「+」を使用します。今まで、特段の説明をせずに使用してきましたが、「+」演算子には数値の加算としての意味と、文字列の連結としての意味があります。
文字列連結演算子は、2つの文字列を連結した新しい String型インスタンスを生成します。文字列を連結するだけで、新しい String型インスタンスが生成されることに注意してください。文字列連結の例を見ていきます。
ソースコードは以下の通り。
I102/I102.java
/** * 文字列連結演算子を使用します。 */ public class I102 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s = "abc"; String t = "def"; String u = s + t; System.out.println("変数 uの内容は " + u); } }
実行結果は以下の通り。
変数 uの内容は abcdef
String型の変数はいくつ宣言されているでしょうか。また、String型インスタンスはいくつ生成されるでしょうか。じっくり考えてみてください。
String型の変数は 3つ宣言されています。そして、String型インスタンスは、合計 5つ生成されます。
イメージとしては以下のような感じです。(1)→(2)→(3)の順番に処理が実行されます。
String型インスタンスが 5つ生成されることが理解できたでしょうか。
文字列連結代入演算子「+=」を使用することもできます。「+=」には、数字の加算代入演算子と文字列連結代入演算子の 2つの意味がある、ということになります。
ところで、この演算子を利用すると、文字列の内容を変更できるように思えるかもしれませんが、String型インスタンスの内容は変更できない…という原則は変わりません。サンプルプログラムを見ていきます。
ソースコードは以下の通り。
I103/I103.java
/** * 文字列連結代入演算子を使用します。 */ public class I103 { public static void main(String[] args) { String s = "abc"; // 文字列連結代入演算子を使用する s += "def"; System.out.println("変数 sの内容は " + s); } }
実行結果は以下の通り。
変数 sの内容は abcdef
イメージとしては以下のような感じです。(1)→(2)→(3)の順番に処理が実行されます。
文字列の内容は変化していない。新しいインスタンスが生成され、そこに参照先が変更されているだけ…ということが分かるかと思います。変更されたのは参照型変数の参照先であって、文字列の内容そのものではない、ということになります。
文字列同士の比較は equalsメソッドを使用します。以前、基本的には「基本型の比較は ==、参照型の比較は equalsメソッド」と記述しましたが、文字列の比較の場合、よっぽど特殊な事情がない限り equalsメソッドを利用します。サンプルプログラムを見ていきます。
ソースコードは以下の通り。
I104/I104.java
/** * 文字列を比較します。 */ public class I104 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s = "abc"; String t = "def"; String u = s + t; String v = "abcdef"; // uと vの文字列の内容を比較する if(u.equals(v)) { System.out.println("uと vの文字列は同じである。"); } else { System.out.println("uと vの文字列は異なる。"); } // uの内容と "abcdef"を比較する if(u.equals("abcdef")) { System.out.println("uの内容は abcdefである。"); } else { System.out.println("uの内容は abcdefではない。"); } } }
実行結果は以下の通り。
uと vの文字列は同じである。 uの内容は abcdefである。
文字列の比較は、よっぽど特殊な事情がない限り equalsメソッドで行います。
なお、NullPointerException発生の可能性が無くなるため、以下のような記述のほうがより安全ではありますが、分かりづらいような気がします。安全をとるか、それとも分かりやすさをとるか、好みが分かれるところです。
if("abcdef".equals(u)) { // 処理 }
空文字列とnullは別物です。以下にサンプルを書いてみます。
String s = ""; String t = null;
変数 sは中身が空の String型インスタンスに紐づいています。変数 uはインスタンスに紐づいていません。
イメージとしては以下のような感じです。
Java SE 7(Java 1.7)の Stringクラスの説明書(API)を掲示しておきます→Stringクラス。
たくさんのインスタンスメソッドを利用することができます。その中でも特によく使うだろうと思われるものを以下にピックアップしました。
これらのうち、splitメソッド以外を実際に利用してみることにします。
ソースコードは以下の通り。
I105/I105.java
/** * String型のメソッドを使用します。 */ public class I105 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s = "AbcDef"; System.out.println("文字列は " + s); // charAtメソッドを使用する(引数は 0スタート) System.out.println("2文字目は " + s.charAt(1)); // indexOfメソッドを使用する System.out.println("「e」は " + (s.indexOf('e') + 1) + "文字目"); // lengthメソッドを使用する System.out.println("文字列の長さは " + s.length()); // substringメソッドを使用する System.out.println("3~5文字目は " + s.substring(2, 5)); // toLowerCaseメソッドを使用する System.out.println("小文字化すると " + s.toLowerCase()); // toUpperCaseメソッドを使用する System.out.println("大文字化すると " + s.toUpperCase()); } }
実行結果は以下の通り。
文字列は AbcDef 2文字目は b 「e」は 5文字目 文字列の長さは 6 3~5文字目は cDe 小文字化すると abcdef 大文字化すると ABCDEF
String型インスタンスは、一度生成したが最後、その内容を変更することは永遠にできない、という特殊な性質がありました。APIが分かった今、改めて調べてみます。
ソースコードは以下の通り。
I106/I106.java
/** * 文字列の確認をします。 */ public class I106 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s = "abcdef"; String t = s.toUpperCase(); System.out.println("変数 sの内容は " + s); System.out.println("変数 tの内容は " + t); } }
実行結果は以下の通り。
変数 sの内容は abcdef 変数 tの内容は ABCDEF
変数 sの内容は、toUpperCaseメソッドを使用しても変化していないことがわかります。
イメージとしては以下のような感じです。(1)→(2)→(3)→(4)の順番に処理が実行されます。
String型のインスタンスの内容は永遠に変えられない、ということを理解できたでしょうか。
MySystemライブラリには getStringメソッドがあり、ユーザから文字列を受け付けることができます。今回は、このメソッドを利用したプログラムを製作してみます。仕様を以下に定めます。
この仕様を満たすソースコードを以下のように製作しました。
I107/MySystem.java
(ライブラリをそのまま利用します)
I107/I107.java
/** * 文字列を変換します。 */ public class I107 { /** * メインメソッド。 * @param args 引数 */ public static void main(String[] args) { String s; s = MySystem.in.getString("文字列を入力してください"); // 出力文字列を作る String t = ""; for(int i = 0; i < s.length(); i ++) { if(i == s.length() - 1) { // 最後の文字の場合 t += s.charAt(i); } else { // 最後の文字以外の場合 t += s.charAt(i) + ":"; } } t = "[" + t + "]"; // 変換後の文字列を出力する System.out.println(t); } }
実行結果の例は以下の通り。
文字列を入力してください? abcdefg [a:b:c:d:e:f:g]