java プログラムの基本単位はクラスです。
クラスにはフィールドとメソッドがあります。
java のオブジェクトには、 タイプ(型)があります。 すなわちクラスがオブジェクトのタイプです。
クラスは、オブジェクトの構造を定義します。 クラス定義は、オブジェクトを生成するためのメカニズムを提供します。
すなわち、クラスを設計図と生産手順マニュアルをもつ工場、 オブジェクトを工場から生産される製品と考えるとわかりやすいでしょう。
クラスの基本は、
フィールド(データ)とメソッド(データを操作するためのコード)です。
クラス Body を見てみましょう。
class Body{ public long idNum; public String nameFor; public Body orbits; public static long nextID = 0; // constructor_1 Body() { idNum = nextID++; } // constructor_2 Body(String bodyName,Body orbitsAround) { this(); nameFor = bodyName; orbits = orbitsAround; } void Earth() { Body sun = new Body("Sun",null); Body earth = new Body("Earth",sun); } }
クラス Body を宣言します。オブジェクトへの参照は以下の通りです。
Body mercury;
クラスの変数はフィールドと呼ばれます。
クラス Body 内の idNum,nameFor,orbits,nextID はフィールドの例です。
ときにはフィールドのインスタンスを、 同じクラスの他のすべてのオブジェクトと共有したいときがあります。 このようなフィールドは static と宣言することで得られます。 クラス内で staticフィールドを宣言すると、 そのクラスから生成されたすべてのオブジェクトは、そのフィールドを共有します。
クラス内のコードからは、
常に同じクラスのすべてのフィールドとメソッドにアクセスできます。
他のクラスのコードからオブジェクトへのアクセスを制限したり、
サブクラスによる継承を制御するため、
以下の4つのアクセス修飾子
のいずれかを指定でき、
その指定順に制限はありません。
以下の表は、アクセス制限の厳しい順に並べたものです。
アクセス修飾子 | 意 味 |
---|---|
private | 自分のクラス以外からは見えない。 |
無指定 [デフォルト] |
アクセス修飾子なしで宣言されたメンバは、 同じパッケージ内のコードからアクセスできます。 また同じパッケージのサブクラスによってのみ継承されます。 |
protected | パッケージ内のほかのクラスおよびパッケージ内外のサブクラスからアクセスできます。 |
public | そのクラスを参照できるすべてのコードからアクセスできます。 またこのメンバはサブクラスに継承されます。 |
質問 | この Body の設計はよくない。どこが悪いのでしょうか? |
クラス定義からオブジェクトを生成することを、 インスタンス化と言います。 このためオブジェクトは、 インスタンスと呼ばれることもあります。
java のオブジェクトはヒープに置かれ、 オブジェクトへの参照を介してのみアクセスできます。 参照すべきオブジェクトがない参照は null です。 参照とは、cでいうポインタのことです。
新しく生成されたオブジェクトは初期状態になります。
通常、フィールドは宣言した値で初期化されます。
単純な初期化では済まないときのために、クラスはコンストラクタをもてます。
コンストラクタは、初期化するクラスと同じ名前でなければなりません。
コンストラクタは引数をもてますが、メソッドではないので、 戻り値はもてません。例えば Body では、具体的な天体を表すオブジェクトは以下のように生成され、 初期化されます。
Body sun = new Body(); sun.idNum = Body.nextID++; sun.nameFor = "Sun"; sun.orbits = null; Body earth = new Body(); earth.idNum = Body.nextID++; earth.nameFor = "Earth"; earth.orbits = sun;
クラスのメソッドには、オブジェクトの状態を知り、操作するコードが含まれます。 メソッドは、オブジェクトへの操作として参照と演算子 . によってよびだされます。
メソッドは、適当な数の引数をもてますが、 可変個の引数をもつものは定義できません。
参照名.メソッド名(引数列);
値を戻さないメソッドの戻り値のタイプは void です。 値を戻すメソッドの戻り値のタイプはオブジェクトの型です。
値を戻すには、以下のようにします。
return 戻り値; ただし、戻り値のタイプは宣言と同じでなければなりません。
メソッドの引数はすべて値渡しです。 つまり呼び出すとき指定した変数値のコピーです。 従って呼び出されたメソッド内で値を変えても、 呼び出し側の値は影響されません。
引数は、() で囲まれた中に書きます。
static でないメソッド内で使うことができる特殊な参照 this は、呼び出されているメソッドの現在のオブジェクトを示します。 参照 this は、 他のメソッドにオブジェクト自身を引数として渡すために使われることが多いです。
フィールドやメソッドの前に参照がないときは、暗黙で this がつきます。
super は、拡張クラスのすべての static でないメソッドから利用できます。
フィールドをアクセスしたりメソッドを呼び出すとき、 super は現在の(super を呼び出した)オブジェクトを、 スーパクラスのインスタンスとみなし、 そのオブジェクトに対する参照として動作します。
super は、参照のタイプにより どのメソッドの実装を使用するかを選択するときに限られます。
class That { protected String nm() { return "That"; } } class More extends That { protected String nm() { return "More"; } public static void main(String[] args) { More m = new More(); m.printNM(); } protected void printNM() { That sref = new More(); System.out.println("this.nm() = "+this.nm()); System.out.println("sref.nm() = "+sref.nm()); System.out.println("super.nm() = "+super.nm()); } }
osaka-43] java More this.nm() = More sref.nm() = More super.nm() = That
スーパクラスの変数とサブクラスの変数が同じ名前だった場合は、 サブクラスの変数がスーパクラスの変数に取ってかわります (スーパクラスの変数を隠す)。 見える方の変数、すなわちサブクラスの変数が、 スーパクラスの変数を覆ってしまいます。
スーパクラスの変数もフルネームを使えばアクセス可能です。
スーパクラス名.変数名でもよいし、
キーワード super を使って super.変数名としてもよいです。
スーパクラスの変数名とサブクラスのメソッド名が同じだった場合やその逆の場合は、
コンパイル・エラーになります。
java のメソッドにはシグネチャがあります。 シグネチャはメソッド名と引数の数とタイプの総称です。
シグネチャが異なる2つのメソッドは、同じ名前をもてます。
これをオーバロードと言います。
public Body orbitsAround() { return orbits; } public void orbitsAround(Body around) { orbits = around; }
クラスのメンバは、フィールドとメソッドの2つです。 static メンバは、各オブジェクトに対して1つづつ存在するのではなく、 クラスに対して1つしか存在できません。
クラスは、static フィールドまたは他の必要な状態を定めるために static 初期化ブロックをもてます。
static 初期化子は、 フィールド宣言での単純な初期化だけでは充分でない場合に有用です。 例えば static な配列を生成し、そのメンバを初期化する場合などです。
class Primes { protected static int [] knownPrimes = new int[4]; static { knownPrimes[0] = 2; for (int i= 1; i< knownPrimes.length; i++) knownPrimes[i] = nextPrime(); } private static int nextPrime(){ ..... } }
static メソッドはクラスに対してよびだされます。普通のメソッドのように、 クラスからインスタンス化されたオブジェクトに対して呼び出されるのではありません。
static メソッドはクラスの static 変数および static メソッドにのみアクセスできます。 特定のオブジェクトのメソッドではないので、参照 this を使えません。 たとえば、上記の static メンバへのアクセスは以下のようになります。
prime = Primes.nextPrime(); knownCnt = Primes.knownPrimes.length;
java はクラスを実行するとき、 そのクラスの main メソッドを探し実行を開始します。
main メソッドは、public かつ static かつ void でなければなりません。 また、引数は String[] 型です。これはプログラム引数で、 クラスを実行するとき入力したものが渡されます。
public static void main(String[] args)
native 指定されたメソッドのことで、 java 言語以外の言語で書かれたプログラムを java から呼び出すためのインタフェースです。 java 言語以外で書かれたコードを使うような java プログラムを書くとき、 またはハードウェアを直接操作する必要があるときは、 ネイティブメソッドを書けます。 ただしネイティブメソッドを使うと、コードの移植性や安全性は失われるので、 最小限にとどめるべきです。
一般的には動的なデータ構造を持つ言語は、メモリが必要になった時に OS に要求し、不要になった時点で OS に戻します。
java では、メモリを解放するのはプログラマではなく、 java の実行コンポネントであるガーベジコレクタです。
ヒープとスタックという概念があります。
スタックは、
手続き呼び出しと戻りに関係する動的なメモリ要求と、
局所変数のための領域として使います。
ヒープは、その他の動的メモリのために使われます。
スタックに確保される変数は、メソッドの局所変数だけです。
オブジェクトはヒープに確保されます。
ガーベジコレクタは、残りのメモリが少なくなったり、 メモリが多量に必要になったとき起動され、 すでに使われなくなったヒープをメモリ領域に戻します。
まとめ |
クラス | フィールド + コンストラクタ + メソッド |
---|---|
オブジェクトの生成 | 変数名 = new クラス名(); |
main メソッド | public static void main(String[] args){} |
メソッドの呼び方
static メソッド クラス名.メソッド名(引数列) static でないメソッド オブジェクト名.メソッド名(引数列)