そもそも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);5staticメソッドなので、クラス名.メソッド名( )という形で使います。この例では、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番目が「お」です。
| 位置 | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| 文字 | あ | い | う | え | お |
最初の引数の位置は含み、二つ目の引数の位置は含みません。そのため、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では、元と同じオブジェクトが返る場合もあります。大事なのは、「元の内容は変わらない」「処理の結果は戻り値で受け取る」という二つです。
質問・コメント
読み込み中この記事についての質問や、学習して気づいたことをお寄せください。
この記事のコメント
コメントを読み込んでいます。