ITエンジニアのプレイングマネージャー化応援サイト

7.文字と文字列の扱い

この記事では、弊社の新人エンジニア研修の参考にJava8を解説します。

前回は配列の作成と使用について解説しました。

今回は文字と文字列の扱いについて解説します。

 

1.文字と文字列の違い

まれに混同される方がいますが、Javaにおいて文字と文字列は別物です。

以下のサンプルプログラムを見てください。

<結果>


どちらも結果は同じですが、c1にはひらがな「あ」の文字コードが、str1には文字列「あ」への参照が入っています。

文字はプリミティブ型、文字列は参照型なのでした。

試しに以下のようなプログラムを実行すると

<結果>

12354

この結果「12354」は、「あ」の文字コードUTF-8を10進数で表現したものです。

 

文字列も内部的には文字の配列として扱われているということはエンジニアの嗜みとして知っておきましょう。

 

IDEを使ってJavaのソースコードを見る事ができます。

詳しい方法は講師から聞いてください。

ここで講師と一緒にJavaのソースコードツアーに行ってみましょう。

Stringクラスのソースコードを見ると113行目あたりに以下の記述があります。

このようにchar型の配列です。

※ちなみに、フィールドがprivate final宣言されているのは後でみるように文字列が一度作成したら中身を変えられない、ということを意味しています。

 

2.Stringクラス

String(標準API) は java.langパッケージに含まれるクラスです。

そのためimport文なしでいきなりソースコード中にStringと記述できるのでした。

Stringは次のようにnew演算子とString()というコンストラクタを使ってインスタンス化することもできます。

※new演算子とコンストラクタについては9.インスタンスの活用のところで詳しく学びます。

しかし、文字列はとても頻繁に使いますので、以下のように簡単にインスタンス化する方法も用意されています。

※しかもこの方法は同じ文字列の場合、インスタンスを使い回すという点でパフォーマンスも優れています。

つまり、Stringは、new演算子を使わなくてもインスタンスを作れる特殊なクラスです。

ただし、実はこの二つのインスタンスの作り方では微妙な違いがあります。

 

3.equalsメソッド

以下のサンプルプログラムを見てください。

結果

false
true

 

ここで、str1~4は参照です。

参照が指し示しているのは”Hello”が格納されている”メモリのありか”です。

str1とstr2は異なる2つのインスタンスが作られています。

ですから、それぞれが格納されているメモリのありかも違っていて、その結果上記のfalseが表示されるのです。

 

==は参照の比較

==は参照の比較

 

対して、str3とstr4では同じ1つのインスタンスを参照しています。

実は、str4を=演算子でインスタンス化したとき、メモリの中を検索して、

同じ文字列”Hello”があれば、それを再利用しているのです。

その結果、trueが表示されたのでした。

 

しろ、Javaの前身はOakという家電組み込み用のプログラミング言語だったのでメモリの節約を考慮したのです。

 

同じ文字列であれば再利用する

同じ文字列であれば再利用する

 

そうすると気をつけなければならないことがあります。

例えば、ログインのシステムを考えてみましょう。

ユーザーが画面から入力したIDとデータベースに格納されているIDを照合するといった処理を考えます。

その際、2つのユーザーIDは別々のヒープ領域に格納されています。

どのようにして同じであるという判断をしたら良いでしょうか?

そんなときには、Stringクラスのequalsメソッドを使います。

<結果>

false
true
2つの文字列が同じであるかどうかを調べるにはequalsメソッドを使う

2つの文字列が同じであるかどうかを調べるにはequalsメソッドを使う

この後、研修が進むと、JSP/サーブレットでログインのシステムを作ります。

その時のために文字列の比較にはequalsメソッドを使わなければならないということを理解してください。

 

 

4.イミュータブル

もう少し、Stringクラスの話を続けたいと思います。

実は、Stringクラスのインスタンスは一度作ったら中身を変えられないのです。

以下のサンプルプログラムを見てください。

<結果>

Hello World

このとき、表示結果には影響ありませんが、5行目でstr1という変数が一旦捨てられて、同じ名前のstr1という変数が作り直されているのです。

Stringクラスのインスタンスは一度作ったら中身を変えられないのです。

このような性質を不変性:イミュータブルといいます。

それを証明する次のようなサンプルコードを見てください。

<結果>

false

もし③でstr1に”World”を代入した時点で参照はそのままで参照が指し示す値だけを上書きしたとしたら、trueとなるはずです。

ですが”World”を代入した時点で(名前は同じ)新たな参照が作成されたため、str1とstr2の参照値は異なりfalseとなった訳です。

Stringクラスがイミュータブルであるということ

Stringクラスがイミュータブルであるということ

これがString型がイミュ―タブル(不変)であるということです。

Javaの設計者がStringをイミュ―タブルにした理由はいつくかありますが、一つはマルチスレッド対応です。

プログラムを複数の処理の流れに分けることをマルチスレッドといいます。

英語のthreadには「」という意味があります。

ある処理(thread)が文字列を処理している途中で別の処理(thread)がその文字列を書き換えてしまうとまずいのですね。

そのため文字列は不変オブジェクトなのです。

さて、理由はさておき実務において、このことはどのような問題があるでしょうか?

 

例えば、大量の文字列の結合を繰り返す場合にパフォーマンスが悪化します。

何千何万回と文字列を結合するような場合には、Stringクラスを「+」で結合するのではなく、

StringBuilderクラスのappendメソッドを使うことをお勧めいたします。

時間が許せば問題集で確認しましょう。

 

 

5.Stringクラスの便利なメソッド

Stringクラスには、(文字のようなプリミティブ型とは違い)文字列を扱うための便利なメソッドが用意されています

そのほんの一部を紹介します。

以下のプログラムでは「新人エンジニアのためのJava研修」という文字列を使って文字列の文字数を数えたり、任意の文字列の出現位置を調べたり、任意の文字列が含まれるか調べたり、任意の文字列を置き換えたりといったことをしています。

結果

17

11
-1

true
false

新人SEのためのJava研修

lengthは、「長さ」という意味なのでlengthメソッドは文字数を返します。

indexOfは、文字列を配列としてみたときの添え字(index)の値のうち、実引数の文字列が最初に現れた添え字を返します。

配列の復習にもなりますが、添字の数え方は以下の通り0始まりです。

文字列も添字は0始まり

文字列も添字は0始まり

 

containsは、「含む」という意味、replaceは、「置き換え」という意味ですので文字通りですね。

他にも色々便利なメソッドがありますからStringの標準APIを探検してみてください。

 

また、後半のシステム開発演習では大きな数値を扱うとき、3桁カンマで表示するようにお願いすることが多いのですが、

それは、このようにして実現できます。

結果

123,456,789

3桁カンマ以外の書式についてはクラスFormatter(標準API)を調べてください。

例えば、円周率の少数点第3位四捨五入2位表示であれば、

System.out.printf(“%.2f”, Math.PI);

のように書くことができます。

 

ここで、注目していただきたいのは、メソッドの呼び出し方です。

String.format(“%,d”, price)

Stringは先頭文字が大文字になっています。

これは、クラスですね。

クラスに属するメソッドということでクラスメソッドまたは、スタティック(static)メソッドと呼ばれます。

staticは静的という意味で、反意語はDynamic(動的)です。

staticはクラスにあらかじめ用意してあるメソッドという意味です。

動的に作り出したインスタンスが持つメソッドではないという意味です。

 

クラスメソッドは、

クラス名.メソッド名

という形で呼び出すことができます。

一方、

str.length()

のようにインスタンスを作ってから、その個々のインスタンスのメソッドを呼び出すのをインスタンスメソッドといいます。

インスタンスメソッドは、

変数名.メソッド名

という形で呼び出します。

 

ここでは、なぜ、クラスメソッドとインスタンスメソッドがあるのかを考察してみましょう。

str.length()は、str(その中身は”新人エンジニアのためのJava研修”)自身が持つ文字列の長さということですから、インスタンスメソッドがふさわしいのです。

インスタンスが変われば文字列の長さも変わりますね。

 

一方、String.format()はintを整形してString(123,456,789)を得るメソッドです。

この処理にはStringのインスタンスが作られる必要性がありません。

最終的な結果として表示される(123,456,789)だけがStringのインスタンスなのです。

そのため、String.format()はインスタンスではなくクラスに属すると考えて、クラスメソッドであるべきなのです。

intに対応するStringを生成するのは、インスタンスには関係のない決まりきった内容の処理だからです。

インスタンスメソッドとクラスメソッドの違い

インスタンスメソッドとクラスメソッドの違い

クラスメソッドは次回のテーマになっていますのでそこでも詳しく学ぶとしましょう。

 

6.エスケープシーケンス

例えばHello と World の間に改行を入れたい場合はどうしたらいいでしょうか?

以下のように、改行を入れたいところには、“¥n”を入れる必要があります。

<結果>

Hello
World

特別な記号や出力方法を制御するためには「¥」記号を使います

この ¥nなどの文字を、「文字本来の意味から逃がした文字列」という意味で、エスケープシーケンス(escape sequence)と呼びます。

この¥記号は日本語版のフォントを使用しているWindows環境の場合です。

それ以外の環境によっては\記号を使います。

※この原稿もソースコードの表記は\記号になっているかと思います。このWebページはLinux上に置いてありますので

もともと英語圏では\記号を使うのですが、日本語圏では金額表示に¥記号を使う必要があったため、

Windowsの前身のOSであるMS-DOSから、日本では\記号を¥記号に置き換えて表示しているという経緯があります。

\記号を¥記号に置き換えるのが一番影響が少ないと考えられたからのようです。

 

当社の新人研修で使用する可能性のあるエスケープシーケンスを紹介します。

 

エスケープシーケンス

意味

\n

改行

\t

水平タブ

\\

\

\’

\”

覚える必要はありませんが、上手く表示できない文字があった時に、ここに戻れるようにしておきましょう。

以下サンプルコードです。

<結果>

“special”price:\3000

 

7.null

ヒープ領域に確保された文字列のための領域を開放するにはどうしたらいいでしょうか?

参照型にnullを代入することで、その参照はインスタンスを参照しなくなり、いずれメモリから消去されます。

Javaにはガーベージコレクションという機構があり、どこからも参照されなくなった文字列は消去されます。

以下のサンプルコードを見てください。

<結果>

ABC
null

“ABC”という文字列は1つですが、この文字列を指し示す参照は”str1″と”str2″の2つがあります。

そして、どこからも参照されなくなった時に、この文字列はガーベージコレクションの対象になります。

nullとは

nullとは

JVMがガーベージコレクションを走らせるのですが、いつ、ガーベージコレクトをするのかをプログラマーの側で指示することはできません。

あくまでプログラマーができるのはガーベージコレクトを依頼することだけです。

 

<まとめ:隣の人に正しく説明できたらチェックを付けましょう>

□文字列の比較にはequalsメソッドを使わなければならない
 
□Stringクラスには、文字のようなプリミティブ型とは違い文字列を扱うための便利なメソッドが用意されている
 
クラスメソッドは、クラス名.メソッド名という形で呼び出すことができ、インスタンスメソッドは、変数名.メソッド名という形で呼び出すことができる
 
□特別な記号や出力方法を制御するためには「¥」記号を使ってエスケープシーケンスを作る
 
□参照型にnullを代入することで、その参照はインスタンスを参照しなくなり、いずれメモリから消去される

 

まとめができたら、アウトプットとして演習問題にチャレンジしましょう。

問題7.文字と文字列の扱い

 

今回は文字と文字列の扱いについて見てきました。

次回は、今回も少し出てきたクラスメソッドについて学びましょう。

 

【今回の復習Youtube】

002-Javaの基本-文字列型の変数と出力

003-Javaの基本-文字列の連結

029-オブジェクト指向の基本-文字列の比較

030-オブジェクト指向の基本-null

031-オブジェクト指向の基本-参照の考え方

053-APIの利用-文字数を取得する

054-APIの利用-部分的な文字列を取り出す

055-APIの利用-書式を変更する

056-APIの利用-文字列から数値に変換する

057-APIの利用-正規表現

 

JavaSE8の解説に戻る

PAGETOP
Copyright © Say Consulting Group, Inc. All Rights Reserved.