【java】クラスとはOS、インスタンスとは仮想コンピュータだ

# 0. オブジェクト指向という「新しい概念」
　プログラミングの初心者で、今までC言語を使ったコーディングの経験しかない人にJavaを教えるのは、思いのほか難しい。<sub><sub>(情報系の大学を想定。1年次にC、2年次にJavaをやる場合が多いそう。)</sub></sub>
「クラスとは何か」と聞かれたら「オブジェクト指向で使う」と説明するが、
「ではオブジェクト指向とは何か」と聞かれたらどうだろう。

「世の中にはいろんなモノゴトがある。そしてモノゴトには状態と振る舞いがある。
だからいろんなモノゴトに対して、状態と振る舞いを集めてクラスの中にコーディングしていく。これがオブジェクト指向だ」
と答えて、相手は納得するかもしれない。
しかし、この後に続く「カプセル化」、「継承」の説明を聞いて、相手は混乱するかもしれない。
いきなり「状態と振る舞いを集めてモノゴトを表現する」と教わったかと思えば、次に「状態を振る舞いに閉じ込める」、「具体的なモノゴトは抽象的なモノゴトをケイショウする」と教わるなど、覚えることが多い。「理論より実践」な人にとっては『苦痛』だろう。
こうして、オブジェクト指向によるコーディングに苦手意識を持ち、プログラミング界隈から離れていく人が、後を絶たないようである。

　『苦痛』の正体は、「オブジェクト指向とは、つまり何か」が一言で説明されないことにある。

　憶測だが、人は新しい概念を、既存の概念になぞらえて考え、誤差の部分は実践により覚える。
天空の城ラピュタで、空に浮かぶ伝説の島ラピュタの発見のために、主人公パズーとシータが政府専用機ゴリアテを尾行するくだりで、一度ゴリアテを見失いそうになる。
そのとき、協力者ドーラは「見張り台」と呼ばれる凧を使って追跡の続行を試みる。
このときパズーは次のよう指示される。
> (凧の)操縦は体で覚えるんだ！

命懸けの無茶ぶりを、難なくこなすパズーの勇敢さが引き立つシーンではあるが、
ドーラも何も考えずにパズーに指示したのではない。ゴリアテ尾行の前、半ば脅されて政府に連行されたシータを救出すべく、ドーラはパズーを乗せてシータの居場所へと小型船を出した。この際、事故の衝撃でドーラは気を失い、小型船は危うく墜落するところであったが、パズーが操縦を急遽代行したことで、九死に一生を得たのだ。
凧の操縦(新しい概念)の指示は、極度に緊迫した状況で小型船を妥当に操縦(既存の概念)したパズーの実績を見込んでのことだろう。

　オブジェクト指向も、同じことではないだろうか。
皆が知っているような何かでオブジェクト指向をたとえ、違いの部分は実践をもとに各々が学習していけばそれでよい。少なくともイメージをつかめずに、手を動かすことすらできないよりはよっぽど。
本記事ではこのようなアプローチでJavaによるプログラミング、およびオブジェクト指向を解説していく。

　最後に補足すると、「プログラムとは何か」、「コンピュータ(計算機でもよい)とは何か」を定義に立ち返って考えれば、
**クラスが「コンピュータを構成できるプログラム」であること、インスタンスがコンピュータであることは論理的に証明可能である**。

# 1. Javaとは「『仮想コンピュータ』を作りまくる言語」だ
　**クラスを一言で説明するなら「コンピュータを構成できるプログラム」である。**
このことは論理的に証明できる。

　同じように、*インスタンスが「仮想コンピュータ」である*ことも証明可能だ。

## 1-1. クラスが「コンピュータを構成できるプログラム」であることの証明 

　まず、ベーム・ヤコピーニの定理[1]にあるプログラムの3要素
「順次」、「反復」、「分岐」を、クラス内のメソッドですべて行える。
ということはもちろん、**メソッドもプログラムといってよい**のであるが、
残念なことにメソッドは「記憶領域」を持たない。
<sub><sub>(蛇足:メソッド内でのみ有効な「ローカル変数」は、メソッド終了時に寿命が尽きるので、「記憶」したとは言えない)</sub></sub>
そのためチューリングマシン[2]における「ヘッダ」を作ることができないため、
**メソッドはプログラムにはなれても、コンピュータにはなれない**のだ。
その点、クラスであれば「フィールド」(java以外の言語なら「プロパティ」などと呼ぶ)を持っていて、これを記憶領域として使うことができるため、
**クラスはコンピュータを構築することが可能**なのだ。(証明終わり)
別の言い方をするならば、クラスとはコンピュータの設計図だ。

## 1-2. インスタンスが「仮想コンピュータ」であることの証明
クラスそのものは、インスタンスという「実体」を作るための型である。
クラスという設計図をもとにインスタンスが生成されるのであるから、
インスタンスは、「クラスという設計図をもとに作った何か」である。
1-1節で証明したことをここに適用すると、
インスタンスとは、
「『コンピュータの設計図』という設計図をもとに作った何か」
である。それは(設計図通りに作れば)コンピュータである。(証明終わり)


# 2. OSと仮想コンピュータを作って遊ぼう
第1章のことより、クラスとは「コンピュータを構成できるプログラム」であり。インスタンスとは「コンピュータ」のことであることが分かった。
「コンピュータを構成できるプログラム」とは、まさにOSである。
不思議かもしれないが、javaでプログラミングするたびに、プログラマはOSを作っているし、`new`するたびに仮想コンピュータを作っているのである。

例えば、次のコードを考えよう。

```java:「Mindows」OSと「computer」コンピュータ
public class Mindows
{
    private byte[] ram;
    public byte getRam(int address){return this.ram[address];}
    public void setRam(int address, byte value){this.ram[address]=value;}
    public Mindows(int ram_size){this.ram = new byte[ram_size];}
}

class Main{ public static void main(String...args)
{
    Mindows computer = new Mindows(64);//64byteのRAMを持つコンピュータの作成
    int i=0;
    for(char each_char : "hello world".toCharArray())
        computer.setRam(i++, (byte)each_char);
        //0~10番地に「hello world」を書き込む

    for(int j=0; j<11; j++)
        System.out.print((char)computer.getRam(j));
        //0~10番地を(charとして)表示
        //→コンソールに「hello world」と表示される。
}}
```
このコードではMindows OSを定義し、このOSの入った仮想コンピュータ`computer`を作って、
RAMを操作している。`computer`(インスタンス)を使ってできることを定義しているのはOS(クラス)であるが、OSが直接何かするわけではなく、実際に動作する実体は`computer`(インスタンス)の方である。

この他にも、
final定数フィールドでROMを作ったり、
finalメソッドでBIOSを作ったり、
ファイル入出力の機能を使ってストレージを持たせたりすることなどが考えられる。

# 3. javaの「実際」に当てはめて考える

## 3-1. ArrayListクラス
`ArrayList<T>`型インスタンスは記憶領域に順番付けて`T`型オブジェクトを格納しておくことのできる仮想コンピュータである。

## 3-2. Listインタフェース
`List<T>`インタフェースは、記憶領域に`T`型オブジェクトを記憶しておくプログラムの「宣言」に過ぎない。**記憶領域の使い方を「おおよそ」決めるもの**といってよいだろう。
`ArrayList<T>`や`LinkedList<T>`は、このインタフェースを「実装」している。
この事実は、`ArrayList<T>`や`LinkedList<T>`が「記憶領域を、`T`型オブジェクトの格納に使う」と宣言していることを意味する。
インタフェースを実装した<sub><sub>有言...</sub></sub>クラスは、インタフェースに定義された空っぽのメソッドをオーバロードし、具体的に定義しなくてはならない。<sub><sub>...実行</sub></sub>

　インターフェースによる宣言は、家電を想像すれば理解しやすい。炊飯器や洗濯機(や、いまの時代では、掃除機も)は、どれもコンピュータといってよいだろう。
炊飯器はコメや水の重さから、炊き上がりの米の硬さや残り時間などを計算してくれる。洗濯機も、自動で判断する場面がある。掃除機は、ルンバをみれば分かるだろう。
今から作るクラス(プログラム)が炊飯器なのか洗濯機なのかはたまた掃除機なのかをはっきり言っておくことは重要だ。また、場合によっては「特定のインタフェースを実装したクラスにだけ、特別な使い方を認める」といったことも出来る。(例えば例外クラスなどがそれである。)

## 3-3. カプセル化
　「コンピュータ内部の回路をお客様にお見せしたくない」―それがカプセル化だ。
第2章に示したコードをもう一度見てみよう。
`computer`のRAMに書き込むとき、わざわざ`setRam(アドレス, 書き込む値)`というメソッドを呼んでいる。
そんなことをしなくても、`ram[アドレス]=書き込む値`ではダメなのだろうか。
もちろん、原理的にはそれで問題ないが、実際には、やりにくくなっている。
「Mindows」開発者は、メモリへの書き込み機能として`setRam(アドレス, 書き込む値)`を作ってはいるが、メモリそのものを剥き出しにはしていないのだ。実際のコンピュータが、メモリを鉄の内側に閉じ込めているように、javaのコード上で`private`というアクセス修飾子を付けている。
このようにすることで、**記憶領域をユーザに勝手にいじられないように**して、誤作動の可能性を低減させている。

#4. OSとコンピュータが自由に作れれば、オブジェクト指向プログラミングが可能
　残念ながらOSをクラスとみることは必ずしもできない。
クラスの持たない概念を持つOSが存在する(というか、ほとんどだ)からだ。
(例: マルチタスクOS、仮想メモリなど。またクロックやCPUを考えなければならない場合は、これをクラスで(実用的に)表現するのは困難であろう)
そこで、クラスが表現できるOSを「クラスOS」、インスタンスが表現できるコンピュータを「インスタンスコンピュータ」あるいは「クラスOSのコンピュータ」と呼ぶことにしよう。

　逆に、クラスの持つ概念(フィールド、メソッドのみとする)のどれかを持たないOSは存在しない。(クラスがOSとみなせることの証明から、明らかである)

　**OSを自由に設計し、そのOSを入れた仮想コンピュータを生成・利用できる環境では、オブジェクト指向による開発が少なくとも部分的に可能**である。(「半オブジェクト指向定理」とでも呼ぼう)
これは、すべてのOSがクラスの概念をすべて持っているため、当然のことである。
エラー発生時には、どのコンピュータ(OS)に不具合が生じたかを確認すればよいためエラーの特定が容易であるし、また仕様変更にも柔軟に対応する。
但し、アクセス制限の仕組みがなければカプセル化は利用できず、コピーの仕組みがなければ継承は不可能だ。

<!--

\# 4-1. 半オブジェクト指向定理の利用(PostgreSQL)

　半オブジェクト指向定理は、オブジェクト指向の導入時に役に立つ。
例えばPostgreSQLのPL/pgSQLでユーザ定義基本型を利用せずにオブジェクト指向を導入したい場合などである。
まず、クラスOSを定義しよう。

```sql
DROP TYPE IF EXISTS Mindows; 
CREATE TYPE Mindows AS (ram bytea, max_size integer); 
--複合型(実態はレコード数0のテーブル)としてMindows OSを作成
```

以上で、複合型として`Mindows型`を定義した。
同時に`ram`やその最大サイズ`max_size`を記憶容量として定義している。
しかし、PostgreSQLでは、型に任意のメソッドを定義することができない。
そこで、

-->

<!-- md5を使ったprivateフィールドの実装も -->


<!--

\## 1-1. 神になって、聖書に好き勝手書いてみよう
<sub><sub>※筆者は神学を勉強したこともなければ、何らかの宗派を信仰する教徒の方でもありません。本記事を読んで不快な思いをされた方がいらっしゃいましたら、申し訳ございません。本記事に出てくる、神学用語の言葉は、以下の定義でオーバロードしています。
・・・
世界$W$に住んでいない($W$の一部でない)にもかかわらず、$W$を造り、改編し、破壊(以下「編集」)できる者を$神(W)$と呼ぶ。
また、$神(W)$が$W$を編集するにあたって用いた言葉を$聖書(W)$と呼ぶ。
世界$W$に進入した$神(W)$、あるいは$聖書(W)$に則って$W$を編集する$W$の住人($W$の一部)を$預言者(W)$と呼ぶ。</sub></sub>

　プログラマは、処理機構の世界の$神(処理機構)$としてとらえることができる。

いきなりではあるが、Javaでコンソールに「'Hello world'」と複数回表示させるクラスを作る例を示す。

```java:Main.java
public class Main
{
    public static void main(String...args)
    //①「実行」開始後すぐよばれる「預言者」だ。
    {//以下は「聖書」そのものだ。
        Greeter g = new Greeter();//Greeterクラスを呼び出す
        g.say(3);//Greeterのsayメソッドを呼び出す
    }
}

class Greeter//② 聖書により呼ばれる
{
    String str;
    Greeter()//③ クラスが呼ばれると、コンストラクタが呼ばれる。
    {
        this.str = "Hello world";
    }
    void say(int times)//④コンストラクタ以外は、呼ばれるまで実行されない。
    {
        for(int i=0; i<times; i++)
        {
            System.out.println(str);
        }
    }
}
```
このコードを実行すると、`g.say(3);`の引数`3`の回数だけ`Hello world`を表示する。
`public static void main(String...args)`メソッドはjavaの中でもとても特別なメソッドであり、**javaが直接実行する唯一のメソッドである**と考えてよい。
プログラマを$神(処理機構)$とするなら、このメソッドは$預言者(処理機構)$メソッドだ。
預言者メソッドには神の言葉がそのまま書かれている。
いわば「聖書」だ。

神が直接人々(オブジェクト)に命令を下すのではなく、
預言者に「あいつにこれをさせろ、そいつにあれをさせろ」と命令するのだ。
そして神に代わって、預言者が他のオブジェクトに対して(聖書に則って)あれこれと命令をし始める。
聖書(＝預言者メソッド)以外のメソッド、クラスなどは、すべて聖書から呼ばれて、<sub>(あるいは聖書から呼ばれた何かに呼ばれて<sub>(あるいは...)</sub>)</sub>初めて実行される。

このような仕組みで、処理機構の世界のすべての者は、神の意向を読み、従うわけである。

\### 1-1-1. 聖書を読んでみよう。
1-1節であげたコードにおいて、聖書の内容は次のとおりである。

```java:mainメソッド内のコード(＝聖書)
        Greeter g = new Greeter();//Greeterクラスを呼び出す
        g.say(3);//Greeterのsayメソッドを呼び出す
```
まず`Greeter`クラスを呼び、
次に`Greeter`クラスの`say`メソッドを呼んでいる。

\### 1-1-2. 聖書に呼ばれるクラス(プログラム)を読んでみよう
ここで、「クラス」という言葉を「プログラム」という言葉に置き換えてみよう。

聖書に呼ばれたGreeterプログラムは次のようになっている。

```java:Greeterプログラム
class Greeter//② 聖書により呼ばれるクラス(＝実行されるプログラム)
{
    String str;//プログラムの記憶領域
    Greeter()//③ クラス(プログラム)が呼ばれると、まずコンストラクタが呼ばれる。
    {
        this.str = "Hello world";
    }
    void say(int times)//④コンストラクタ以外は、呼ばれるまで実行されない。
    {
        for(int i=0; i<times; i++)
        {
            System.out.println(this.str);
        }
    }
}
```
`Greeter`プログラムは、メモリとして`str`というものを持っている。
また、機能`say`を実行することも出来る。

聖書の1行目で`Greeter`プログラムが呼ばれた際には、
コンストラクタにてメモリ`str`に`Hello world`を記録させている。
これは初期化の作業である。
そして聖書の2行目で`say`メソッドが呼ばれると、引数に指定された回数だけ、
メモリ`str`の内容をコンソールに表示する。

\## 1-2. 

-->

#n.参考
[1]http://s150001.skr.u-ryukyu.ac.jp/lectures/index.php?ProgrammingAbility
[2]http://e-words.jp/w/%E3%83%81%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%83%9E%E3%82%B7%E3%83%B3.html