この国では犬が

本と芝居とソフトウェア

プログラミング言語Java 第4章 インタフェース

ちょっとあいだがあきました。

 

インタフェース!

 

オブジェクト指向設計の基本的な単位であるところの型、その純粋な型を定義するのがインタフェースとの由。

 

4.1 簡単なインタフェースの例

インタフェースは「できる(-able)こと」を表現することが多い。

インタフェースを実装するクラスは、そのインタフェースのメソッドすべてを実装するか、abstractとする必要がある。

インタフェース型の参照を使用して、Objectクラスのすべてのメソッドを呼び出すことができる。なぜなら、すべてのクラスは暗黙にObjectクラスを継承しているから。(そして、もちろん、そのオブジェクトの「実際の型」が固有に持つメソッドは、キャストしない限り呼び出すことができない)

 

4.2 インタフェース宣言

インタフェースには以下3種類のメンバーを宣言でき、すべてのメンバーは暗黙にpublicである。

  • 定数(フィールド)
  • メソッド
  • ネストしたクラスとインタフェース

 

4.2.1 インタフェース宣言

インタフェースは、名前付定数を宣言できる。

そして、ネストする列挙型の定数も宣言することができる。

それから、修正可能なオブジェクトを保持する名前付定数を宣言できる。なぜなら、参照がfinalでも、オブジェクトはconstではないからね……。まあ、ここではそれは便利なことだ。と思う。

 

4.2.2 インタフェースメソッド

インタフェースのメソッド宣言には、修飾子として、暗黙に付加されるpublicとabstractを除いては、アノテーションだけを付加することができる。

 

4.2.3 インタフェース修飾子

インタフェース宣言には、メソッドに付加可能なアノテーション、public、abstractに加えて、strictfpも付加することができる。(ただし、メソッドがstrictfpになるわけではなく、定数とネストした型だけ!)

 

4.3 インタフェースの拡張

インタフェースは、extends予約語を用いて拡張できる。多重継承も可能。

よって、たとえば、SerializableRunnableインタフェースを宣言することができる。

 

4.3.1 定数の継承と隠蔽

定数は継承されるし、また隠蔽されるけど、どのみちstaticなのでその辺を気にする必要は普通あんまない。

 

4.3.2 メソッドの継承、オーバーライド、オーバーロード

CardDealerインタフェース(draw()メソッドを持つ)とGraphicalComponent(draw()メソッドを持つ)を多重継承したGraphicalCardDealerインタフェースの問題。

ね、これ、ありますよね……。そしてこれソリューションが提示されてないけど、どうしたらいいのでしょうか!引数ありメソッドなら、おそらく引数の型が違ってくるから大丈夫だけど、引数なしメソッドは、ダメだ。アノテーションシグネチャには含まれないから、使えない。……まあ、ありがちなケースって気がするので、たぶんいいやり方があるものでしょう。(考えるのをやめた)

 

そーいやインタフェースの名前って、別に形容詞じゃなくてもいい感じなのですね。しかし、名前からクラスかインタフェースか判別できないの、一貫性なくて嫌な感じしますけど……。

 

4.4 インタフェースを使用する

Attributedインタフェース。Iterableインタフェースを拡張しない。

 

4.4.1 インタフェースを実装する

AttributedImplクラス。Iterableインタフェースを実装する。

 

4.4.2 実装を使用する

AttributedImplを使用するには、継承と、コンポジションとの2種類の手がある。

そういやコンポジションで、Pimplとか出てこない、ていうかヘッダファイル自体ない、その辺の考え方どうなってるのかしら。

 

4.5 マーカーインタフェース

メソッドも定数も持たないインタフェース。

そして、Cloneableはマーカーインタフェース(!!)

そういえば……clone()はObjectクラスのメソッドであって、別にObjectクラスがCloneableを継承しているわけではない!(何となくその辺もやっとしてました)

 

そんなわけで、Cloneableインタフェースの宣言は結構衝撃的。

interface Cloneable {

}

潔い。

 

4.6 いつインタフェースを使うか

C++との機能的な違いって観点でざっくりまとめると、結局、実装の多重継承を禁止して、その代替として型だけを多重継承できるインタフェースがあるってことになる……と理解している。

機能じゃなくて、コミュニケーションの観点では、C++の「実装の提供も多重継承も可能な抽象クラス」より、Javaの「実装を提供できるけど多重継承不可能な抽象クラス」と、「実装は提供できなくて多重継承は可能なインタフェース」の組み合わせの方が、メッセージが明確になるので、優れているように思う。

 

---

 

そういや、ようやくJDKをインストールしてコード書いてみるなどしました。

4.4.2読んでるときにも思ったけど、そういや#include的なものはなくていいのか、javacコマンドが、そのクラスから使用してるクラスを自動的に全部判別、コンパイルしてリンクしてくれるのか?前回から変更のあった部分だけいい感じにコンパイル&リンクしてくれるのか……とか、結構謎が多い。

 

それから、練習問題3.11(ソートアルゴリズムのメトリクス集計用クラスのセキュリティホール発見とその修正)は解けたけど、ライセンス的に本に載ってるコードを転載できない感じがするので公開するのがメンドイ感じです。。

ちなみに前回口走ったprobe()で配列コピーすればあとはソートし放題じゃん!の案は、ダメでした!(ソートを遂行するには与えられた配列のオブジェクト自体を操作しないといけなくて、probe()は配列の個々の値のコピーを返すだけなので……)

やっぱコード書いてみないとわからないことがある。

 

まあとりあえず、練習問題は適宜やりつつ、基本的には読み通すの優先でチャキチャキ進めていく所存です。