Javaプログラミング基礎 講義資料

参照

クラスは「型」の一種であるという話をしましたが、 厳密にはクラスとして宣言された変数と int, double などとして宣言された変数の性質は異なります。

具体的には、例えば以下の 2 つの宣言による変数の性質は異なるということです。

int counter;
ShoppingCart myCart;  (ShoppingCart は別の場所で定義されているクラスとします)

ここで、「型」の性質を述べるために以下の分類をします。

(基本型のことを「プリミティブ型」と呼ぶこともあります)

Java のルール

基本型
参照型

イメージ

基本 (プリミティブ) 型の変数を考えてみましょう。

int counter = 4;

この場合、変数 counter には「4」という値そのものが格納されます。

 

 

では、参照型ではどうなるのでしょうか。

ShoppingCart myCart = new ShoppingCart();

この場合、変数 myCart には ShoppingCart のオブジェクトの在りかを示す 参照 (オブジェクトを指し示す矢印のようなもの) が格納されます。

 

 

重要: ShoppingCart オブジェクトそのものが変数に格納されるのではありません。 格納されるのはその在りかに関する情報です。

参照を理解するための練習

参照型のイメージをつかみましょう (1): 参照型の変数の宣言とオブジェクトの生成、代入

次のような変数宣言とオブジェクトの生成を考えてみましょう。

Dog koro = new Dog();

 

  1. Dog koro = new Dog();
    

    下線部分 Dog koro は koro の変数宣言部分です。 koro は Dog クラスのオブジェクトの在りかが格納される変数ということになります。

  2. Dog koro = new Dog();
    

    下線部分 new Dog() は、 Dog クラスのオブジェクトを生成する式です。 この部分が実行されると、データを入れたりメソッドを実行する オブジェクト (実体) が用意されます。

  3. Dog koro  =  new Dog();
    

    イコールを使用すると、 2 で生成したオブジェクトの「在りか」が koro に代入されます。 すなわち、 koro の指し示す先は、 2 で生成されたオブジェクトだということになります。

     

     

参照のイメージをつかみましょう(2): 変数の代入

参照型の変数には、 そのオブジェクトへの参照が格納されます。 次のプログラムを見てみましょう。

  1. Dog pochi = new Dog();
    Dog koro  = new Dog();
    

    Dog クラスのオブジェクトを示す変数を 2 つ宣言し、 Dog のオブジェクトを生成しています。 2 つの変数にはそれぞれ Dog オブジェクトへの参照を代入しています。

     

     

  2. Dog myFavorite = pochi;
    

    変数 myFavorite を新たに宣言し、 変数 pochi の値を代入しています。 これにより myFavorite に pochi の情報がコピーされることになります。

    ここで重要なことは、 myFavorite には pochi と同じオブジェクトへの 参照が格納されているということです。 myFavorite と pochi は同じオブジェクトを指し示すことになります。

    元々 pochi の指し示していたオブジェクトは、 myFavorite という変数を通じても使うことができます。

     

     

  3. pochi = koro;
    

    おや、 koro の値を pochi に代入してしまいました。 こうすると、pochi の指し示すオブジェクトが koro と同じものになります。 元々 koro の指し示していたオブジェクトは、 pochi という変数を通じても使うことができます。 (同じ犬なのに pochi と koro の 2 つの名前を持つことになりました)

     

     

    ここで myFavorite について考えてみましょう。 pochi の指し示す先が変わっても、 myFavotite の指し示す先は変わりません。

参照のイメージをつかみましょう(3) オブジェクトの生と死

  1. Dog pochi = new Dog();
    Dog koro  = new Dog();
    

    Dog クラスのオブジェクトへの参照を格納できる変数を2つ宣言し、 Dog クラスのオブジェクトを2つ生成しています。 2 つの変数にはそれぞれオブジェクトへの参照を代入しています。

     

     

  2. pochi = koro;
    

    koro の値を pochi に代入しています。 pochi の指し示すオブジェクトが koro と同じものになります。 元々 koro の指し示していたオブジェクトは、 pochi という変数を通じても使うことができます。

    さて、ここで元々 pochi の指していたオブジェクトはどうなるのでしょう。

    このオブジェクトは、どの変数からも参照されていない状態となります。 Java では、どの変数からも参照されていない状態となったオブジェクトは、 プログラムの中で不要になったものだとして自動的に消滅させられます。 この機能をガーベージコレクション (garbage collection) と呼びます。

     

     

    (CやC++には、ガーベージコレクションの機能はありません。 プログラムの中で不要になったオブジェクトやデータは 明示的に領域の開放を行う必要があります。 きちんと開放されないと永久にメモリ上に存在することになります。 このようなことから起こるプログラム不具合をメモリリークと呼びます。)

  3. pochi = null;
    

    pochi に null を代入しています。 null とは、「何もオブジェクトを指し示していない」ことを表す特別な値です。 pochi はどのオブジェクトも指し示していないので、 pochi を使ってメソッドを実行するなどの意味のある仕事はできません。

    一方、koro の指し示すオブジェクトは、 まだ変数 koro によって参照されています。 koro の指し示すオブジェクトがガーベージコレクションによって 消去されることはありません。

     

     

String クラス

今回の2つめの話題は文字列についてです。

これまでの例題では、 文字列を String というキーワードを用いて、 宣言し利用してきました。 実は Java では、文字列もオブジェクトとして扱っています。 クラス String は、 文字列を表すクラスであり、 あらかじめ Java のクラスライブラリに存在しているクラスです。

クラス String は少し特殊な性質を持っています。

クラス 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 のオブジェクトが表す文字列の内容が同一であるかを調べるには、 比較演算子 == を用いることができません。 クラス String メソッド equals を用います。

例えば、String のオブジェクト str1str2 の内容が同一であるかを 調べるには以下のように書きます。

if (str1.equals(str2)) {
    ...
    等しい場合の処理
}
else {
    ...
    異なる場合の処理
}

メソッド equals は、自らのオブジェクト (上の例では str1) の内容と、 引数で与えられたオブジェクト (上の例では str2) の内容を比較し、 等しい場合には true を、異なる場合には false を返します。

文法的には以下のようになります。

基準となるStringのオブジェクト . equals ( 比較したいStringのオブジェクト )

String クラスの利用

実は、クラス String にはメソッド equals 以外にも、 様々なメソッドがあらかじめ用意されています。 その中で、主要なものを紹介します。

int length()
この文字列の長さを返します。
例:
String message = "California Girls";
System.out.println(message.length());

(文字列 message の長さ 16 が表示される)
int compareTo(String anotherString)
2 つの文字列を辞書式に比較します。 この String オブジェクトが辞書式に引数文字列より前にある場合は、結果は負の整数になります。この String オブジェクトが辞書式に引数文字列の後ろにある場合、結果は正の整数になります。文字列が等しい場合、結果は 0 になります。
例:
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 + "より辞書順で後ろ")
int indexOf(int ch)
この文字列内で、指定された文字が最初に出現する位置のインデックス (最初から数えて何番目かの文字か) を返します。 該当する文字がこの文字列内にない場合は、-1 が返されます。
例:
String message = "California Girls";
char ch = 'a';

System.out.println(message + "には" + ch + "という文字が" +
                   message.indexOf(ch) + "文字目にあります");
int indexOf(String str)
この文字列内で、指定された文字列が最初に出現する位置のインデックスを返します。文字列が見つからない場合は -1 を返します。
String message = "California Girls";
String keyword = "Girl";

System.out.println(message + "には" + keyword + "というキーワードが" +
                   message.indexOf(keyword) + "文字目にあります");
String replace(String target, String replacement)
この文字列内に引数で指定された文字列 target が含まれていた場合、 それを文字列 replacement に置換し、その結果を新たな文字列として返します。 この文字列自身は変更されません。
String message = "California Girls";
System.out.println(message.replace("Girls", "Boys");

(message の中の "Girls" の部分が "Boys" に置き換えられて表示される)

他にもたくさんのメソッドがあります。 Java SE 6.0 APIドキュメント を参照してください。

クラスライブラリ

このドキュメントから分かるように、 実は Java には様々なクラスがあらかじめ用意されています。 このように再利用可能なクラス集をクラスライブラリと言います。

また、クラスライブラリの一部は、 プログラムと外部とのインタフェースであることから、 API (Application Program Interface) と呼ばれます。

残念ながらこの講義では、 クラスライブラリの内容全てを取り上げることは不可能です。 しかし、 Java でプログラムを効率的に開発するためには、 クラスライブラリは非常に有効です。 また、ウィンドウ、アイコン、ボタン等の GUI の部品や、 画面入出力やファイル入出力のためのストリームも クラスライブラリに含まれます。

クラスライブラリを使いこなすことが上達への早道です。

修飾子

今回取り上げる 3 つめの話題は修飾子です。 修飾子は、クラスの属性やメソッドを、 他のクラスからアクセスできるようにするかどうかや、 変数の書き換えを禁止させるかどうか といった様々な設定を行うためのものです。

クラスの利点の1つに、他のオブジェクトに対してクラス内部の細かい情報を 見せなくても、メソッドの実行の組み合わせでプログラムを書くことができる という点があります。 クラス内部の情報である属性は、外部オブジェクトから直接値を書き換えたり 参照したりせずに、公開されたメソッドを通じてのみ 変更や参照を行う方が好ましいのです。 これにより、意図しない属性の使われ方を防ぐことができます。

以下に、属性とメソッドに対するアクセスレベルについて説明します。

public

オープンなアクセスレベルは public です。 public メンバは外部に対して公開され、 任意のクラスからアクセスすることが可能です。 例えば、外部から実行されるメソッドは public にします。

public のメンバを宣言するには、 宣言時にキーワード public を使用します。

private

最も厳しいアクセス制限レベルは private です。 private のメンバは、 そのクラスの中でのみアクセス可能となります。 外部からアクセスされたくない属性や、 外部から実行されたくないメソッドを private にします。

private のメンバを宣言するには、 宣言時にキーワード private を使用します。

次の例は、クラス Person の各属性を private にし、 各メソッドを public にした場合のプログラムです。

属性 age を private にし、public なメソッドを介してアクセスすることで、 意図しない値 (例えば、負の数や年齢としては大きすぎる値) を直接代入することを防いでいます。

class Person {
    private String name;  // 名前
    private int age;      // 年齢

    public void setName(String n) {
        name = n;
    }

    public void setAge(int a) {
        if (a > 0 && a < 120)
            age = a;
        else
            System.out.println("不正な年齢の値です:" + a);
    }
}

指定なし

これまでのプログラムでは、 main メソッドを除いて、 修飾子を特に指定しませんでした。

この場合、 そのクラスのファイルが存在する 同じディレクトリ内にあるすべてのクラスに対しては、 メンバにアクセス可能となります。 (これは「同じパッケージ内では公開される」という決まりなのですが、 パッケージについての詳しい内容は本講義では取り扱わないこととします。)

private, public などのアクセス範囲を決めるキーワードは、 いずれか一つのみを指定することしかできません。

その他の修飾子

変数のその他の修飾子

クラスの属性や局所変数 (ローカル変数) の宣言時に指定することができる 修飾子に以下のものがあります。

final で指定された変数は、 宣言時に初期化し、それ以降値の変更ができないことを示します。

プログラムの中で一度決めたら途中で変更することがない定数として用いる場合、 キーワード final を用いて変数宣言を行います。 以下に、簡単な例を示します。

public Circle {
    // 円周率 PI を 3.14 に初期化
    private final double PI = 3.14;
    ...

    public void somethingToCalculate() {
        // 自然対数の底 E を 2.72 に初期化
        final double E = 2.72;
        ...
    }
}

なお、上の変数 PI の宣言のように、 キーワード final は private, public などの他の修飾子と組み合わせて使うことができます。

static については、後の回で扱います。

メソッドのその他の修飾子

private, public などアクセス範囲を指定する修飾子に加えて、 メソッドに指定することができる修飾子に以下のものがあります。

static については、後の回で扱いますが、 その他の修飾子については本講義では扱いません。 皆さんの自習にまかせることにします。