![]() ![]() ![]() ![]() |
オブジェクト、クラス、インタフェース |
MyClass の aFloat のようにメンバ変数を宣言する時、このコードはインスタンス変数を宣言する。 クラスのインスタンスを作成する度に、実行時システムはインスタンスのためにクラスのインスタンス変数の各コピーを作成する。オブジェクトの使用で説明するように、オブジェクトからオブジェクトのインスタンス変数にアクセスすることができる。class MyClass { float aFloat; }「PENDING: クラスのインスタンス化とインスタンス変数のコピーの図」
インスタンス変数は、(
static
修飾子を使用して宣言する)クラス変数と対照的である。 実行時システムは、そのクラスの作成するインスタンス数にかかわらず、クラス毎にクラス変数を割り当てる。 システムは、クラスを検出した最初の時にクラス変数のためにメモリを割り当てる。 すべてのインスタンスがクラスのクラス変数の同じコピーを共有する。 インスタンスあるいはクラスそれ自身を通してクラス変数にアクセスすることができる。「保留:クラス vars の picture か?」
メソッドも同様。クラスはインスタンスメソッドとクラスメソッドを持つことができる。 インスタンスメソッドが現在のオブジェクトのインスタンス変数を操作するが、クラス変数にもアクセスできる。 また一方では、クラスメソッドはクラス内で宣言したインスタンス変数にアクセスすることができない(新規のオブジェクトを作成したり、オブジェクトを通してアクセスしないならば)。 また、クラスメソッドはクラス上で呼び出すことができる。クラスメソッドを呼び出すためのインスタンスは不要である。
デフォルトでは、特に指定されなければ、クラス内で宣言するメンバはインスタンスメンバである。 以下に定義するクラスには、インスタンス変数 (
x
という名前の整数)と他のオブジェクト設定をして、x
の値に問い合わせる2つのインスタンスメソッド(setX()
と
x()
)がある。。クラスから新規のオブジェクトをインスタンス化する度に、クラスの各インスタンス変数の新規コピーを得る。 これらのコピーは新規のオブジェクトと関連がある。 クラスから新規の AnIntegerNamedX オブジェクトをインスタンス化する度に、新規の AnIntegerNamedX オブジェクトと関連があるclass AnIntegerNamedX { int x; public int x() { return x; } public void setX(int newX) { x = newX; } }x
の新規コピーを得る。「 PENDING:x インスタンス変数を持っている AnIntegerNamedX の 図」
すべてのクラスのインスタンスがインスタンスメソッドの同じ実装を共有する。すべての AnIntegerNamedX のインスタンスは同じ
x()
と
setX()
の実装を共有する。x()
と
setX()
の両方のメソッドは、オブジェクトのインスタンス変数x
を名前で参照するので注意すること。 「もしすべての AnIntegerNamedX のインスタンスがx() および setX()
と同じ実装を共有すれば、 これは曖昧ではないか」という疑問があるだろう。 答えはノーである。インスタンスメソッド内では、インスタンス変数名は現在のオブジェクトのインスタンス変数を参照する(インスタンス変数がメソッドパラメータにより隠されないと仮定した場合)。 それで、x() と setX()
内では、x
はthis.x
と等しい。. . . AnIntegerNamedX myX = new AnIntegerNamedX(); AnIntegerNamedX anotherX = new AnIntegerNamedX(); myX.setX(1); anotherX.x = 2; System.out.println("myX.x = " + myX.x()); System.out.println("anotherX.x = " + anotherX.x()); . . .
setX()
で myX
に x
値をセットしたが、anotherX.x の
値が直接に割り当てたので注意すること。 いずれかの方法で、コードは x
の2つの異なるコピーを操作している。1つは myX
オブジェクトに含まれ、1つは anotherX
オブジェクトに含まれる。 このコードの一部が作り出した出力は、クラス AnIntegerNamedX の各インスタンスはインスタンス変数myX.x = 1 anotherX.x = 2
x
自身のコピーをもち、各 x
が異なる値を持っていることを示している。
メンバ変数を宣言する時、変数がインスタンス変数ではなくクラスであることを明示することができる。 同様に、メソッドがインスタンスメソッドではなくクラスメソッドであることを明示することができる。 システムは、変数が定義されるクラスを初めて検出した時に、クラス変数のコピーを作成する。 そのクラスのすべてのインスタンスがクラス変数の同じコピーを共有する。 クラスメソッドはクラス変数でのみ操作することができる。それらはクラスで定義したインスタンス変数にアクセスすることができない。
メンバ変数がクラス変数であることを明示するためには、 static
キーワードを使用する。 例えば、 x
変数がクラス変数であるように、 AnIntegerNamedX クラスを変更する。
AnIntegerNamedX の2つのインスタンスを作成する前述した 全く同じコードだが、class AnIntegerNamedX { static int x; public int x() { return x; } public void setX(int newX) { x = newX; } }
x
の値を設定したら、次のような異なる結果になる。myX.x = 2 anotherX.x = 2
x
がクラス変数となったため、出力は異なる。それは変数のコピーは1つだけあり、そしてそれが myX
と anotherX
を含むすべての AnIntegerNamedX のインスタンスにより共有される。 いずれかのインスタンス上に setX()
を呼び出すと、 x
の値がすべての AnIntegerNamedX のインスタンスへセットされる。
1つだけのコピーを必要とする項目にはクラス変数を使用する。そのクラス変数は、変数が宣言されるクラスから継承しているすべてのオブジェクトからはアクセス可能でなければならない。 例えば、定数を定義するためによく final
でクラス変数を使う(これは定数が変更できないほどのメモリ効果があるので、コピーは実際に1つだけでよい)。
同様に、メソッドを宣言すると、インスタンスメソッドではなくクラスメソッドになるメソッドを指定することができる。 クラスメソッドはクラス変数でのみ動作することができ、クラスで定義するインスタンス変数にアクセスすることができない。
メソッドがクラスメソッドであることを明示するためには、メソッド宣言で static
キーワードを使用する。 メンバ変数 x
がもう一度インスタンス変数になり、その2つのメソッドがクラスメソッドになるように、 AnIntegerNamedX クラスを変更する。
AnIntegerNamedX のこのバージョンをコンパイルしようとすると、コンパイラエラーになる。class AnIntegerNamedX { private int x; static public int x() { return x; } static public void setX(int newX) { x = newX; } }
これは、メソッドが最初に AnIntegerNamedX のインスタンスを作成し、それを通して変数にアクセスしないと、クラスメソッドはインスタンス変数をアクセスすることができないからである。AnIntegerNamedX.java:4: Can't make a static reference to nonstatic variable x in class AnIntegerNamedX. return x; ^ AnIntegerNamedX.java:7: Can't make a static reference to nonstatic variable x in class AnIntegerNamedX. x = newX; ^ 2 errors
その x
変数をクラス変数にして、 AnIntegerNamedX を修正する。
これで、クラスはコンパイルし、 前述したコードはAnIntegerNamedX の2つのインスタンスを作成し、class AnIntegerNamedX { static private int x; static public int x() { return x; } static public void setX(int newX) { x = newX; } }
x
値を設定してから、次の出力を生成する。myX.x = 2 anotherX.x = 2
myX
を通して x
を変更すると、 AnIntegerNamedX の他のインスタンスの xも変更される。
インスタンスメンバとクラスメンバのもう1つの相違は、クラスメンバがクラス自身からアクセス可能ということである。 そのクラスメンバをアクセスするためにクラスをインスタンス化する必要がない。 AnIntegerNamedX クラスから直接 x()
と
setX()
をアクセスするために、前述の コードの一部を書き換える。
. . . AnIntegerNamedX.setX(1); System.out.println("AnIntegerNamedX.x = " + AnIntegerNamedX.x()); . . .
myX
と anotherX
を作成しなくてもよいことに注意する。 x
を設定して、そして AnIntegerNamedX クラスから直接 x
を検索することができる。 インスタンスメンバに対してはこれを行うことができない。オブジェクトからインスタンスメソッドを起動するだけや、オブジェクトからインスタンス変数にアクセスするだけは可能である。 クラスのインスタンスあるいはクラス自身からクラス変数とクラスメソッドをアクセスすることができる。
![]() ![]() ![]() ![]() |
オブジェクト、クラス、インタフェース |