クラスは「型」の一種であるという話をしましたが、 厳密にはクラスとして宣言された変数と int, double などとして宣言された変数の性質は異なります。
具体的には、例えば以下の 2 つの宣言による変数の性質は異なるということです。
int counter; ShoppingCart myCart; (ShoppingCart は別の場所で定義されているクラスとします)
ここで、「型」の性質を述べるために以下の分類をします。
(基本型のことを「プリミティブ型」と呼ぶこともあります)
基本 (プリミティブ) 型の変数を考えてみましょう。
int counter = 4;
この場合、変数 counter には「4」という値そのものが格納されます。
では、参照型ではどうなるのでしょうか。
ShoppingCart myCart = new ShoppingCart();
この場合、変数 myCart には ShoppingCart のオブジェクトの在りかを示す 参照 (オブジェクトを指し示す矢印のようなもの) が格納されます。
重要: ShoppingCart オブジェクトそのものが変数に格納されるのではありません。 格納されるのはその在りかに関する情報です。
次のような変数宣言とオブジェクトの生成を考えてみましょう。
Dog koro = new Dog();
Dog koro = new Dog();
これにより koro という名前の変数が作られます。 koro は Dog クラスのオブジェクトの在りかが格納される変数ということになります。 しかし、まだ、この時点では koro には具体的な在りかは 格納されていません。
Dog koro = new Dog();
これにより Dog クラスのオブジェクトが生成されます。
Dog koro = new Dog();
イコールを使用すると、 2 で生成したオブジェクトの「在りか」が koro に代入されます。 すなわち、 koro の指し示す先は、 2 で生成されたオブジェクトだということになります。
参照型の変数には、 そのオブジェクトへの参照が格納されます。 次のプログラムを見てみましょう。
Dog pochi = new Dog(); Dog koro = new Dog();
Dog クラスのオブジェクトを示す変数を 2 つ宣言し、 Dog のオブジェクトを生成しています。 2 つの変数にはそれぞれ Dog オブジェクトへの参照を代入しています。
Dog myFavorite = pochi;
変数 myFavorite を新たに宣言し、 変数 pochi の値を代入しています。 これにより myFavorite に pochi の情報がコピーされることになります。
ここで重要なことは、 myFavorite には pochi と同じオブジェクトへの 参照が格納されているということです。 myFavorite と pochi は同じオブジェクトを指し示すことになります。
元々 pochi の指し示していたオブジェクトは、 myFavorite という変数を通じても使うことができます。
pochi = koro;
おや、 koro の値を pochi に代入してしまいました。 こうすると、pochi の指し示すオブジェクトが koro と同じものになります。 元々 koro の指し示していたインスタンスは、 pochi という変数を通じても使うことができます。 (同じ犬なのに pochi と koro の 2 つの名前を持つことになりました)
ここで myFavorite について考えてみましょう。 pochi の指し示す先が変わっても、 myFavotite の指し示す先は変わりません。
Dog pochi = new Dog(); Dog koro = new Dog();
Dog クラスのオブジェクトへの参照を格納できる変数を2つ宣言し、 Dog クラスのオブジェクトを2つ生成しています。 2 つの変数にはそれぞれオブジェクトへの参照を代入しています。
pochi = koro;
koro の値を pochi に代入しています。 pochi の指し示すオブジェクトが koro と同じものになります。 元々 koro の指し示していたオブジェクトは、 pochi という変数を通じても使うことができます。
さて、ここで元々 pochi の指していたオブジェクトはどうなるのでしょう。
このオブジェクトは、どの変数からも参照されていない状態となります。 Java では、どの変数からも参照されていない状態となったオブジェクトは、 プログラムの中で不要になったものだとして自動的に消滅させられます。 この機能をガーベージコレクション (garbage collection) と呼びます。
(CやC++には、ガーベージコレクションの機能はありません。 プログラムの中で不要になったオブジェクトやデータは 明示的に領域の開放を行う必要があります。 きちんと開放されないと永久にメモリ上に存在することになります。 このようなことから起こるプログラム不具合をメモリリークと呼びます。)
pochi = null;
pochi に null を代入しています。 null とは、「何もオブジェクトを指し示していない」ことを表す特別な値です。 pochi はどのオブジェクトも指し示していないので、 pochi を使ってメソッドを実行するなどの意味のある仕事はできません。
一方、koro の指し示すオブジェクトは、 まだ変数 koro によって参照されています。 koro の指し示すオブジェクトがガーベージコレクションによって 消去されることはありません。
今回の2つめの話題は文字列についてです。
これまでの例題では、 文字列を String というキーワードを用いて、 宣言し利用してきました。 実は Java では、文字列もオブジェクトとして扱っています。 クラス String は、 文字列を表すクラスであり、 あらかじめ Java のクラスライブラリに存在しているクラスです。
クラス String は少し特殊な性質を持っています。
クラスからインスタンスを作成するためには、 new 演算子を用い次のように書くのでしたね。
String str = new String("Hello");
ただし、クラス String に限り、 上記のように new 演算子を用いる以外に次のようにして インスタンスを生成できます。
String str = "Hello";
この式の右辺のように、 文字列をダブルクォーテーション (") で括って記述することで、 String のインスタンスを生成することが可能です。 このように Java では、ダブルクォーテーションで括り記述された文字列は、 全て String のオブジェクトとして扱われることになっています。
次の例は String のインスタンスを生成する式です。
new String("Hello, Java.") "Java progamming is easy." "Linux" + " is also easy." "I have studied Java for " + day + " days."
特に、上の例の 3 番目や 4 番目のように、 プラス (+) 演算子を用いて文字列や数値を連結させることができます。 そして、連結した結果の文字列のオブジェクトが新たに生成されることになります。
また、本講義では扱いませんが、 自由に文字列を追加したり、長さを変更できるクラスに StringBuffer があります。
String のオブジェクトが表す文字列の内容が同一であるかを調べるには、 比較演算子 == を用いることができません。 クラス String の メソッド equals を用います。
例えば、String のオブジェクト str1 と str2 の内容が同一であるかを 調べるには以下のように書きます。
if (str1.equals(str2)) { ... 等しい場合の処理 } else { ... 異なる場合の処理 }
メソッド equals は、自らのオブジェクト (上の例では str1) の内容と、 引数で与えられたオブジェクト (上の例では str2) の内容を比較し、 等しい場合には true を、異なる場合には false を返します。
文法的には以下のようになります。
基準となるStringのオブジェクト . equals ( 比較したいStringのオブジェクト )
実は、クラス String にはメソッド equals 以外にも、 様々なメソッドがあらかじめ用意されています。 その中で、主要なものを紹介します。
例: String message = "California Girls"; System.out.println(message.length()); (文字列 message の長さ 16 が表示される)
例: String girls = "California Girls"; String boys = "California Boys"; if (girls.compareTo(boys) == 0) System.out.println(girls + "と" + boys + "は等しい") else if (girls.compareTo(boys) < 0) System.out.println(girls + "は" + boys + "より辞書順で前") else // girls.compareTo(boys) > 0 System.out.println(girls + "は" + boys + "より辞書順で後ろ")
例: String message = "California Girls"; char ch = 'a'; System.out.println(message + "には" + ch + "という文字が" + message.indexOf(ch) + "文字目にあります");
String message = "California Girls"; String keyword = "Girl"; System.out.println(message + "には" + keyword + "というキーワードが" + message.indexOf(keyword) + "文字目にあります");
String message = "California Girls"; System.out.println(message.replace("Girls", "Boys"); (message の中の "Girls" の部分が "Boys" に置き換えられて表示される)
他にもたくさんのメソッドがあります。 JDK 5.0 ドキュメント、 もしくは、 /usr/java 以下に展開した同様のドキュメントを参照してください。
このドキュメントから分かるように、 実は Java には様々なクラスがあらかじめ用意されています。 このように再利用可能なクラス集をクラスライブラリと言います。
また、クラスライブラリの一部は、 プログラムと外部とのインタフェースであることから、 API (Application Program Interface) と呼ばれます。
残念ながらこの講義では、 クラスライブラリの内容全てを取り上げることは不可能です。 しかし、 Java でプログラムを効率的に開発するためには、 クラスライブラリは非常に有効です。 また、ウィンドウ、アイコン、ボタン等の GUI の部品や、 画面入出力やファイル入出力のためのストリームも クラスライブラリに含まれます。
クラスライブラリを使いこなすことが上達への早道です。