ジェネラル
そういえば前回の記事に掲載したtest1、test2クラスの意味を述べていなかった。
このクラスは、クラスとインスタンスに対する理解を深めるため自分用に作ったものだ。
一番の疑問は、クラス変数がいつ生成されるか?であった。
次に疑問だったのは、インスタンス内部のmainメソッドは動作しているのか?であった。
そして、staticの有る無しでどのようなアクセス制限がなされるのか?であった。
明らかに後半に寄り道をしたが、実験を通してクラスとインスタンスの関係が分かってきた。
そして同時に、なぜ今までこうもクラスとインスタンスが分かりにくかったのかの原因が分かったのだ。
■クラスとインスタンスとは
私が考えるクラスとインスタンスのイメージを述べておこう。
まず、性質として
・クラスはデータ型として扱うことができ、その型で変数(ここではインスタンスつまりオブジェクト)を宣言・定義することができる。
・クラスはデータだけでなくデータの操作・出力プログラムであるメソッドを内蔵できる。インスタンスもメソッドを持てる。それらに外部からアクセスしすることも、変更することも、それをさせないように設定することもできる。
・インスタンスを宣言・生成しなくてもクラス変数・クラスメソッドにはアクセスできる。
・static修飾子がつくとクラス変数・クラスメソッドになる。
・クラス変数・クラスメソッドはインスタンス全てにおいて共通で、参照可能。
・クラスメソッドからクラス自身のインスタンス変数・インスタンスメソッドを参照する事は出来ない。
が、挙げられる。
これらを列挙しても一般に言われる”クラス”と”インスタンス”は「設計図」と「製品」、というイメージが私には沸いて来ない。
なぜなら設計図は製品のように機能を持ってはいないからだ。
そもそもメモリー上の電子的存在を物質的存在で譬えようという事に無理があるのだが、私もチャレンジしてみる。
”クラス”と”インスタンス”は「版木」と「印刷物」である。
版木を元に印刷物を作る。印刷物はそれ独自の機能(お金だったり、本だったり)があるが、版木のほうにも別の機能があるのである。そして「版木と印刷物の設計図」が”クラスファイル”である。
しかしまあ、こんなのはしょせん言葉遊びに過ぎない。どんな例えを用いても正確に伝える事は出来ないからだ。
だが、ここで重要なことに気がついた。多くの解説書では、”クラスファイル”と”クラス”がごっちゃになっているのだ。
ここでちょっとメモリー上のデータを想像して欲しい。
生成された(メモリー上にコピーされた)インスタンス全てのメモリ領域にクラス変数とクラスメソッドが保持されているだろうか?否であろう。100や200もインスタンスが生成されたらとんでもないメモリの無駄遣いになるし、クラス変数の変更のたびに全てのインスタンスの保持するクラス変数データを書き換えなければならないなんてCPUの無駄遣いである。つまり、インスタンスそれぞれのクラス変数の部分は、メモリー上のある特定の場所(ここにクラス変数の値が入っている)を示して終わりになっていると考えるのが正解だろう。
一方、アクセスにより自動的に生成されているクラス変数とクラスメソッドは(例え既にインスタンスが生成されていても)インスタンス変数・インスタンスメソッド(およびその中のローカル変数)を参照できない。これは無いのと同じことだと思う。実際メモリー上には無いだろう。これまたメモリー領域の無駄だからだ。(インスタンスメソッドの命令部分だけはクラスに残されている可能性はある。インスタンスメソッドはローカル変数だけ保持して、命令部分はクラスから参照するほうがメモリーの節約になるからだが、説明が面倒になるし検証する方法もないのでここでは無視する。)
つまり、メモリー上にはインスタンスに属するデータ・メソッド領域と、クラスに属するデータ・メソッド領域があり、お互いに共通する部分はほとんど無い。ゆえにこのクラスはけしてインスタンスの設計図ではない。
だからこの”クラス”と、元になった”クラスファイル”は同一ではない。クラスはクラスファイルのインスタンス部分がごっそり抜け落ちており、クラス変数も初期値とは異なっている可能性がある。そして重要な事は、プログラムが実行中にデータ・メソッドを扱わなければならない対象はクラスファイルではなくクラスの方なのである。
さて、再び譬えに挑戦してみる。
クラスが元々の英語の意味通り「階級」(日本語的に言えば江戸時代での「身分」・もしくはインドの「カースト」)を意味するのであれば、クラスファイルとクラスとインスタンスはこう説明できるだろう。
クラスファイルは「ある階級の定義=実例を挙げる(考え出す)ことのできる常識」
クラスは「その階級の一般的・平均的人物のデータ・振舞い方の集合体」
インスタンスは「その階級のある特定(実際)の人物のデータ・振舞い方の集合体」
を、意味する。
そもそもインスタンスとは”instance”で、「実体」ではなく「場合・事実・実例・事例」を意味する。高校生なら”for instance”で「例えば」という意味であることを知っているだろう。
つまりクラスメソッドは「この階級の人間なら必ずこう答える・行動する」と期待される抽象的・イメージ的なものであり、インスタンスメソッドはそれ以外の「実際の個人に特徴的な振る舞い」を意味する具体的なものと言える。
クラス変数がインスタンス変数の合計や平均であったりすると分かりやすいが、メモリー上に乗っているクラスは設計図ではなく、「この階級において一般的なデータ・行動」なのである。そこでハードディスク上のクラスファイルと、メモリー上のクラスとを区別するために、後者をジェネラル”the general”(一般・通則・概要・総則)と呼ぶことにする。
以下にクラスファイルとクラス(=ジェネラル)とインスタンスの関係を図示する。
「参照可・不可」の部分にはデータが無いと考えてほしい。見ての通りお互いのメモリ領域にに共通するデータは存在しない。この様にジェネラルとインスタンスは割り符のように、クラスファイルを断ち割って生成されるものなのだ。
あるいはクラスファイルが満月とすると、ジェネラルが三日月だったら出来るインスタンスは二十六夜月なのである。
或は騙し絵のように、長方形がクラスファイルなら、中央の燭台がジェネラルで、向かい合った顔がインスタンスなのである。
この意味で、ジェネラルはインスタンスの型(クッキー用の型抜きの型など)であると言ってもいいだろう。
残念ながらこの様な図は、これまで読んできた解説書には載っていなかった。大抵の本はクラスファイルからインスタンスを生成する絵があるのみで、ジェネラルを無視している。
かろうじて
「Javaによるプログラミング入門:久野 禎子, 久野 靖」
にはこれに近い図が描かれているが、クラスとメソッドが所有する変数・メソッド間の関係と相互の参照関係について記述が無く、読者の理解を助けるものとは言いがたい。
私はイメージを持つことで物事を理解するタイプなので、文字ばかりとか、理解を助ける役に立っていないイラストばかりの解説書を読んでもサッパリである。世の中たくさんのJava本が出ているが、総じてそんな本ばかり。Java技術者という人種はイメージではなく文字列のみで理解できる人たちばかりなのであろうか?まったくもってウラヤマシイ限りである。
ってそんなわけネーだろッ!
いろんな人間が書いてんだから
ちったあマシなイラスト載っけた
解説書があってもいいだろが!!
手ぇー抜いてんじゃねぇぇぇッ!!!