補足記事

そもそもStringって何?

文字列を扱うときに使っているStringは、実はJavaが用意しているクラスです。文字列リテラルとの関係や、length・substringなどの使い方を通して、Stringの仕組みを見てみましょう。

Stringクラス??

 初めはStringが何なのかよく分からないまま、ただ単に文字列を保持する変数だと思って使う人が多いと思います。私も、こんなに基本的なものなのに、なぜ基本データ型に含まれていないのかな?と思っていました。

 Stringと、基本データ型のboolean、byte、char、short、int、long、float、doubleには、見た目の違いもありますね。基本データ型は全部小文字ですが、Stringは頭文字が大文字です。

 Stringは、Javaの標準ライブラリに用意されているクラスです。クラス名の頭文字を大文字にするのはJavaでの命名の慣習で、Stringもそれに従っています。

 Stringクラスはjava.langパッケージにあります。別のパッケージのクラスを使うには、通常はパッケージ名を含めて書くか、importしますが、java.langのクラスは内部でこっそりimportされています。そのため、java.lang.Stringと書かなくても、Stringだけで使えます。

 なお、String型の変数とStringオブジェクトは別物です。変数には、オブジェクトを指す参照値が入ります。この点は、基本データ型と参照型の違いでも説明しています。

文字列リテラルはオブジェクト?

 String型の変数を宣言して文字列を代入するのは、簡単ですね。以下の使用例は、それぞれStringExample.javaのmainメソッド内に書く部分を抜き出しています。

StringExample.java

String s = "あいうえお";

 クラスのインスタンスを作るときは、newを使うと習ったと思います。Stringにも、次のような書き方があります。

StringExample.java

String s = new String("あいうえお");

 これはStringのコンストラクタに文字列を渡し、同じ内容を持つ別のStringオブジェクトを作っています。しかし、普通に文字列を使いたいだけなら、ここでnewを書く必要はありません。

 ソースコードの中で、ダブルクォーテーションで囲んだ文字列を文字列リテラルと言います。Javaでは、"あいうえお"という文字列リテラル自体が、Stringオブジェクトへの参照を表すようになっています。

 つまり、new String("あいうえお")は、既にStringオブジェクトを表しているものを引数にして、もう一つStringオブジェクトを作っているわけです。

StringExample.java

String s = "あいうえお";

 これで、文字列リテラルが表すStringオブジェクトへの参照を、変数sに代入できます。同じ文字列リテラルは同じStringオブジェクトを共有するので、書くたびに必ず新しいオブジェクトが作られるわけではありません。

Stringクラスが文字列を保持できるわけ

 Stringクラスの中身を見たことはありますか?文字列も、コンピュータの中では文字を表すデータの並びとして保持されています。

 例えば、JDK 8のStringクラスには、次のようなフィールドがありました。これは自分で書くコードではなく、当時のString.javaの一部です。

String.java

private final char value[];

 char型の配列ですね。char value[]は、char[] valueと同じ意味です。私は後者の書き方の方が、配列だと分かりやすくて好きです。

 charはUTF-16の1コード単位を保持する基本データ型です。「あ」や「い」はそれぞれ一つのcharで表せるので、それを並べれば「あいうえお」のような文字列を表せます。charについては、基本データ型の説明も参照してください。

 内部の保存方法を意識しなくても、Stringが用意しているメソッドを通して文字列を扱えます。長さを知りたいときに使うのが、length()です。

StringExample.java

String s = "あいうえお";
System.out.print(s + "の文字数は" + s.length() + "文字です");
実行結果
あいうえおの文字数は5文字です

 length()は、そのStringの長さをint型の戻り値として返すインスタンスメソッドです。この例では5を返します。

length( )とlength

 よく似たものに、配列で使うlengthがあります。( )があるかないかの違いです。

StringExample.java

int[] a = new int[]{1, 2, 3};
System.out.print(a.length);
実行結果
3

 配列もオブジェクトです。配列のlengthは、要素数を表すpublic finalのフィールドなので、( )を付けずに参照します。

書き方何を使っているか得られる値
s.length()Stringのメソッド文字列の長さ
a.length配列のフィールド配列の要素数

 片方はメソッドを呼び出し、もう片方はフィールドの値を読む、と考えれば、( )の有る無しにも納得がいきますね。

その他、Stringクラスのメソッド

 Stringにはlength()以外にも、いろいろなメソッドが定義されています。ここでは、よく使うものを二つ紹介します。

valueOf:数値などを文字列にする

 まずはstaticメソッドのvalueOfです。int型の値を渡すと、その数値を表す文字列を返します。

StringExample.java

int i = 5;
String s = String.valueOf(i);
System.out.println(s);
実行結果
5

 staticメソッドなので、クラス名.メソッド名( )という形で使います。この例では、intの5をStringの"5"に変換しています。

 valueOfには、doubleやboolean、オブジェクトなどを受け取る形も用意されています。このように同じ名前で引数の型などが異なるメソッドを用意することを、オーバーロードと言います。

substring:文字列の一部分を取り出す

 次は、インスタンスメソッドのsubstringです。文字列の一部分を、戻り値として受け取れます。

StringExample.java

String s = "あいうえお";
String t = s.substring(1, 4);
System.out.println(t);
実行結果
いうえ

 文字の位置は0番から数えます。0番目が「あ」、1番目が「い」、4番目が「お」です。

位置01234
文字あいうえお

 最初の引数の位置は含み、二つ目の引数の位置は含みません。そのため、substring(1, 4)で取り出すのは1番目から3番目までの「いうえ」です。少しややこしいですが、終わりの位置の直前まで、と考えてください。

 では、valueOfとsubstringを組み合わせてみましょう。生年月日を表す19770101というint型の値を、「1977年01月01日」という文字列に変換します。

StringExample.java

int birthday = 19770101;
String strBirthday = String.valueOf(birthday);
String year = strBirthday.substring(0, 4);
String month = strBirthday.substring(4, 6);
String day = strBirthday.substring(6, 8);
String strBirthday2 = year + "年" + month + "月" + day + "日";
System.out.println(strBirthday2);
実行結果
1977年01月01日

 数値を文字列にし、年・月・日の部分をそれぞれ取り出して、間に「年」「月」「日」を挟んで連結しています。この例は、必ず8桁になる値を使っています。

 Stringには、ほかにも便利なメソッドがたくさんあります。StringのAPIドキュメントで、それぞれの使い方を確認できます。

書き換えられないString

 最後に、初心者がつまずきやすいポイントを見てみましょう。

StringExample.java

String s = "あいうえお";
s.substring(1, 4);
System.out.println(s);

 このとき、何が表示されるでしょうか?

実行結果
あいうえお

 「いうえ」にはなりません。substringは元の文字列を書き換えるメソッドではなく、取り出した部分の文字列を返すメソッドです。上のコードでは、その戻り値を受け取っていないので、sは元のままです。

 そもそも、Stringオブジェクトは、一度作ったら内容を変更できません。この性質を「不変(immutable)」と言います。文字列を操作するメソッドも、元のオブジェクトを変更せず、結果を返します。

 結果を使いたいなら、先ほどのように別の変数tに代入するか、次のようにsに代入し直します。

StringExample.java

String s = "あいうえお";
s = s.substring(1, 4);
System.out.println(s);
実行結果
いうえ

 この場合も、元の「あいうえお」というオブジェクトを書き換えたわけではありません。変数sが、「いうえ」という結果のオブジェクトを指すようになったのです。

 また、文字列を扱うメソッドが、必ず新しいオブジェクトを作るとは限りません。例えば文字列全体を指定したsubstringでは、元と同じオブジェクトが返る場合もあります。大事なのは、「元の内容は変わらない」「処理の結果は戻り値で受け取る」という二つです。

全講座の目次へ戻る

質問・コメント

読み込み中

この記事についての質問や、学習して気づいたことをお寄せください。

コメントを書く

投稿フォームを準備しています。

コメントと一緒に公開される名前です。
3,000文字以内。パスワードなどの個人情報は書き込まないでください。

コメントは送信後すぐに公開されます。

この記事のコメント

コメントを読み込んでいます。