クラス定義の内部で定義されている変数の事を一般的に「フィールド」と呼びます。
フィールドは基本的にprivateで定義すべきです。
そうする事によってそのフィールドはクラススコープとなり外部からの不用意なアクセスを防ぐ事ができます。
→カプセル化 特にstaticモディファイアが付加されたフィールドをクラスフィールド/クラスメンバと呼びます。
クラスフィールドと区別する為に「インスタンスフィールド(メンバ)」とも呼びます
ちなみに、変数という言葉に関してはJavaでは基本的にローカル変数(メソッド内で定義されるもの)を 意味しますが、フィールドやローカル変数を総称して変数と呼ぶ事もあります。
→クラス変数/インスタンス変数といった感じです。
staticフィールドをこのように呼びます。 Javaではstaticはクラス定義内でしか使用できません(メソッド内では使えない)。
クラスフィールドはクラスに対して一つの領域しか保持しない代わりに、
そのクラスがインスタンス化されていなくても 存在しつづけます(静的メンバとも呼びます)。
クラス定義の内部で定義されているクラスまたはオブジェクトの操作インターフェイスです。
特にクラスに対する操作をクラスオペレーション/クラスメソッドと呼びます。
オペレーションそのものはCにおける関数とほとんど同じで、複数の入力パラメタと
復帰値を定義できます。
異なる部分はそれが特定のクラス(のオブジェクト)に属しており、クラスの内部データにアクセスできる唯一
の手段であるというところです。
フィールドをpublic(より厳密にはprivate以外)にしてしまうと外部から内部データの操作ができてしまいます。
フィールドは基本的にprivateとしましょう。
static(静的)なオペレーションの事であり、そのクラスのオブジェクトが存在しなくても呼び出す事ができます。
一般にそのクラスの特定のインスタンスに対してではなくクラス自身の属性を操作したり、
そのクラスのインスタンス全体に対する操作を行いたい場合に定義します。
public staticなクラスオペレーションはどこからでも呼び出せてしまう為、Cにおける「関数」と
ほとんど同じように使えてしまいますが、そのような使い方は推奨されません。
Cの関数ライブラリと同じようなものとしてjava.lang.Mathやjava.awt.Toolkitのようなクラス
も存在しますが、かなり特殊な使われ方であり賛否が分かれています。
上記クラスは対象オブジェクトに持たせる事に無理があるようなメソッドだけを集めている 事を考えると、われわれがそのようなメソッドのライブラリを作る場合には細心の注意が必要です。
自分自身を継承したクラスをサブクラスと呼びます。 サブクラスから見た自分自身はスーパークラスと呼びます。
C++では派生クラス/基底クラスとも呼ぶみたいです。
サブクラスは基本的にスーパークラスのすべてのフィールドとオペレーションを継承します。
つまり、サブクラスで定義されているかのように使うことができます。
※ただし、コンストラクタは継承されません
サブクラス上で既に スーパークラスにある オペレーションと同一の オペレーションを定義した場合、 サブクラスで定義した オペレーションが優先されます。 これをオペレーションのオーバーライドと呼びます。
この機能によって、スーパークラス で既に定義されている機能に拡張機能を付加したり異なる動作をさせることができます。
インターフェイスの意味を壊すような異なる動作をさせるのは良くありません。
ただし、デザインパターンにもあるように、アルゴリズムを抽象化したインターフェイスの場合、オーバーライドされた物毎に全く意味の異なる処理となる場合もあり得ます。(それでも抽象化された意味を壊してはならない)
そして、オーバーライドによって定義されたオペレーションの呼び出し文によって、呼び出されるオペレーションは、そのオブジェクトのクラスに定義されたオペレーションとなります。
呼び出そうとした時の変数の型(静的な型)とは無関係です。
つまり、その呼び出し文の個所が実行される時のオブジェクトに応じて呼び出されるオペレーションが変わることになり(ダイナミックバインディング/動的結合)、これをポリモーフィズムと呼びます。
同一とは、パラメタ/戻り値の型まで一致していると言う意味です。 パラメタの型(個数)が異なる場合はオーバーロードと呼び、 これは別の意味があります。
Javaでは(C++でも)同名オペレーションを定義しても オペレーションの型またはパラメタの型 (=シグネチャ)が異なる場合は 別のオペレーションとみなされます。
この機構をオペレーションのオーバーロードと呼びます。
※オーバーライドと混同しないようにしましょう。
Javaにおいては、パラメタ個数が同じでそのパラメタ型が異なるオーバーロードされたオペレーションを呼び出そうとすると、以下のように複数のメソッドを呼び出せる可能性が出てきます。
class Foo {}
class Bar extends Foo {}
:
void method(Foo foo) {}
void method(Bar bar) {}
:
Foo foo = new Bar();
method(foo);
この場合、オーバーライドの説明に習うと、method(foo);の呼び出しではmethod(Bar
bar)が呼び出されるように見えます。
(上記のダイナミックバインディングの説明を見てください)
しかし、実際には呼び出されるのはmethod(Foo
foo)の方です。
つまり、オーバーロードはオーバーライドと異なり、静的に呼び出し対象が決まります。
なぜそのようになったかの理由はいろいろあるのですが、以下の例を見てください。
interface Foo {}
interface Bar {}
class Hoge implements Foo, Bar {}
:
void method(Foo foo) {}
void method(Bar bar) {}
void method(Hoge hoge) {}
:
Foo foo = new Hoge();
method(foo);
これをダイナミックバインディングで解決しようとすると、パラメタに渡されたオブジェクトはHogeクラスのインスタンスとなり、それはFooでもありBarでもあるわけです。これでは何を呼び出してよいか解らないのでエラーとするしかないですね。
静的に解決する(つまりは変数の型によって決める)ようにする場合は、method(Foo
foo)が呼び出されることになります。
interface Foo {}
interface Bar {}
class Hoge implements Foo, Bar {}
:
void method(Foo foo) {}
void method(Bar bar) {}
:
Hoge hoge = new Hoge();
method(hoge);
先程の例と比べるとmethod(Hoge hoge)が無い訳ですが、つまりは変数の型であるHoge型にマッチするメソッドは無いわけです。オペレーションのオーバーロードを用いるのが好ましいのは コンストラクタ及び、同じ動作を実現する手段をいくつか提供したい場合です。 パラメタの型が異なるだけで動作がまったく異なるようなオーバーロードは行わないようにしましょう。
修飾子とも呼ばれます。定義文の手前に付加する構文で、その定義に対する属性を指定します。
Javaでは以下のようなモディファイアが存在します。
詳細はJava言語仕様を参照してください。
クラスを実体化したものをインスタンスと呼びます。また、クラスを実体化する事を「インスタンス化する」といいます。
Cっぽく言えば「そのクラス型の領域をmallocで取得する事」といった感じです。
オブジェクトという言葉はもっと広い意味で使われます。
厳密にはクラスもインスタンスもオブジェクトであり、「クラスのオブジェクトを作る」というと、そのクラス自身なのかクラスのインスタンスを作る事なのか不明瞭です。しかし、一般的には後者を指すようになっています。
コンストラクタはオブジェクトが生成される時に実行される
オペレーションであり、 クラス名と同一の名前を持ちます。
具体的にはnew クラス名();と表記することでそのクラスの
インスタンス を生成すると共にコンストラクタを呼び出し、
インスタンス の初期化処理を行います。(インスタンス≒オブジェクト)
コンストラクタはオペレーションである為、パラメタを取る事ができます。
コンストラクタをオーバーロードする事により、 パラメタの与え方によって初期設定内容を変える事ができるようになります。
コンストラクタは復帰値を持ちませんので定義時に復帰値の記述は行いません。
Javaの世界ではオペレーションのパラメタの型/パラメタの並び/復帰値の型の全てをひっくるめて
シグネチャと呼びます。
シグネチャが異なれば、同名オペレーションでも別のオペレーションとなります(オーバーロード)。
クラスファイルをグループに分ける単位です。
クラスのフルネームはパッケージ名。クラス名です
詳細はJavaの言語仕様を参照。
インスタンス化を禁止したクラスの事を言います。
詳細はJava言語仕様を参照してください。
実装を記述しないオペレーションを抽象オペレーションと呼びます。
抽象オペレーションが存在するクラスは必ず抽象クラスになります。
サブクラスで実装を記述する事を前提にされたオペレーションです。
中で行うことを決めてしまわないことで、サブクラス作成者にそのメソッドの実装を記述することを強制することに意味があります。
抽象オペレーションを用いずに、デフォルトの実装(標準的な実装または空の実装)を定義しておくことで、サブクラス作成者にオーバーライドを強制しないような設計もあります。
詳細はJava言語仕様を参照してください。
抽象メソッド及び、static finalフィールド(変更不可の意)のみが
定義された「クラスのようなもの」です。
機能的には抽象クラスに近いのですが、概念的な意味はかなり異なります。
下の「実装」を修正したことでやっと気付いたんですが、ここのドキュメント群を書いた当時は「インターフェイス」と「interface」の使い分けを(記述上で)ちゃんとしていなかったようです。直そうと思ったけど結構多岐にわたるので・・・。
「インターフェイス」は一般的には特定のもの同士のやりとりの取り決めであり「仕様」です。直訳で「界面」とも呼ばれます。
それに対してJava言語上での「interface」はキーワードの"interface"を差し、クラスの仕様部分のみを記述する為の言語機能です。
interface Hoge {
void foo();
void bar();
}
とあったとき、Hoge interface(または「interface Hoge」)のインターフェイスはfoo()とbar()である。
と行った使い分けが割と一般的にされています。
インターフェイス(メソッド)の実処理部分を記述する事を言います。
JavaではinterfaceをClassにimplementsすることも指しますが、厳密には区別すべきです。
一般的に言う「実装」と(Javaのキーワードである)「implements」は、どちらも実装なんですが、区別され得る概念です。
class Foo implements Bar {
:
}
と書いたときにFooはBarを実装する、と呼んだりしますが、これはimplementsに書いたことをもって「実装する」といっているというよりは、Barに宣言されたメソッドの実装(実処理)を記述するんだ、ということをもって「実装」といっていると解釈すべきです。
なぜ、そんなごたくを書くかというと、implements=実装と解釈してしまうと、より一般的な意味で「実装する」と表現する人との間で誤解が生じてしまう為です。
[JavaHouse-Brewers:26901]でわかりやすく説明されておられますが、個人的解釈を加えて言えば、
interface Hoge extends Foo, Bar {}
はinterfaceの多重継承。
class Hoge implements Foo, Bar {}
はinterfaceの多重実装。より誤解なく言うなら、「HogeはFooとBarを(多重に)implementsしている」といいます。
繰り返しますが、「実装する」といえば一般には単にコードを記述することです。Java言語において「implements」しているからといって「実装している」とは限りません。それは以下の例から明らかです。
interface Bar {
void hoge();
}
abstract class Foo implements Bar {} // <-
Barをimplementsしているがメソッドhoge()を実装していない
同様のパターンで、「インターフェイス」(界面/仕様などとも言う)と「interface」も使い分ける必要があります。
優しい読者の方にご指摘いただきましたので修正しました。直さなきゃいけないところは他にもいっぱいあるんですが、見直す余裕がないのですT_T & _o_。このドキュメントは古いですが、間違いを放置するわけにもいかないのでお気づきの点があればお気楽に文句いってくださいまし_o_。
クラス内の全てのデータ(フィールド)をprivateとし、外部からアクセス出来ないようにすることです。
外部からはそのクラスのメソッドを呼ぶ事しか許されません。
もちろん、各メソッドはクラス内のフィールドの情報を利用して処理を遂行して、適切な結果を返します。
つまり、クラス内のフィールドの内容が外部から不用意に壊されないことが保証された安全設計ということですね。
クラス宣言の内部、またはメソッド宣言の内部で、新たなクラスの宣言を行ったばあい、そのクラスはinner classと呼びます。
inner classにはstaticクラスとnon staticクラスがあります。
static inner classはクラス宣言が他のクラス宣言の内部にあるということ以外は通常のクラスト同様に扱えます。
これは、packageよりも狭義の名前空間を与えていると考えて、そのクラスからしか生成しないオブジェクトなどを作るのに役立ちます。
non static inner classはouter class(inner classを宣言しているクラス)のオブジェクトからしか生成することができません。その代わり、そのouter classオブジェクトの全てのフィールドに直接アクセスすることができます。
和名は厳密な定義がありません。anonymous classと称します。
クラス名を定義せずにクラス宣言を行ったものです。つまりは、オブジェクトさえ利用出来れば、クラスの名前を決めなくてもよいという状況での便宜を図ったものです。
宣言の仕方は、メソッドなどの実行文中で、特定のインターフェイスを実装したオブジェクトが必要な場合に、そのインターフェイスを持ったクラスまたはinterfaceを継承/実装した新たなクラスをその場で宣言してnew します。
void method() {
Runnable r;
r = new Runnable() {
public void run() {
:
}
};
Thread t = new Thread(r);
t.start();
}
これでRunnableを実装した新たなクラス宣言を用意しなくても、クラス名を持たないRunnable実装クラスの宣言を行っていることになります。
(この場合はnew Thread() { public void run()
{ ・・・ } };の方がよい)
配列の初期化子に似た構文なので、使い心地はかなり良いですが、乱用はしないようにしましょう。
直訳では(オブジェクトの)「直列化」となりJavaにおける実際の使用方法は以下のようになります。
直訳すると「役割」。オブジェクト指向プログラミングでは物事の属性と動作をまとめて
「オブジェクト」と定義していて、「世の中すべてオブジェクト」みたいな世界観がある
(こともあった)のですが、実際にはオブジェクトとして定義するよりこの「role」(役割)
として定義付けた方がすっきりする事が多くあります。
(特に設計の初期段階でこの区別をしっかりした方が拡張性に優れたクラスになる)
Javaでは「role」に相当するものとして「interface」が言語使用でサポートされています。
じゃあ、どういうものがroleなのかというと、たとえば「従業員」というオブジェクトが存在する
時、従業員というのは「人間」クラスから派生してくるクラスになると思われますが、人間クラス
に対してどのような属性を付加して「従業員」クラスを生成するのでしょう。
実は人間クラスと従業員クラスの間には「従業員としての役割」の付加しか行わないのが自然です。
こんな事を書くと、従業員の属性として「月給」とかがあるじゃんってことになりますが、
上の文は「属性を付加しない」という意味ではありません。
外(この場合「雇用者」としましょう)から見て「従業員」クラスとの関係(association)は
「雇用関係」にあるといえますが(この関係が1対1か1対多になるまで詳細に分析すべきです)、
「雇用者」「従業員」とも他方が存在しないと存在し得ないものである(単独で意味を成さない)為、
これらはクラス(またそのオブジェクト)ではなくroleである、ととらえます。
Javaのinterfaceの効果の一つにこの「役割を定義付ける」ことがあげられます。
雇用者が従業員に要求する事は従業員の「役割」であり、interfaceには「役割」だけを記述
する事が許されているのです。
(参考)Byじゃずさん
(参考)もういっちょ
上にちょこっと書いてますが、関係/関連と言った意味で使われます。
上記のように「会社」(雇用者)/「人」(従業員)の関係は「雇用関係」にあるといい、このような関連名
をassociationと呼ぶようです。
JavaおよびHotJavaは米国Sun Microsystems社の商標または登録商標です。