インターフェイス
Javaにおけるインターフェイス
インターフェイスはインスタンス化出来ない。クラスによって実装(implement)されるか、拡張(extends)されるだけです。
APIとしてのインターフェイス
インターフェイスと多重継承
Javaでは多重継承を許容していません。
インターフェイスを定義する
public interface HogeInterface extends Interface1, Interface2 {
// メソッドシグネクチャ
}
publicをつければ、任意のパッケージの任意のクラスでも利用可能となる。
publicとつけなければ、同一パッケージ内からのみ利用可能となります。
インターフェイス本体
インターフェイス中に宣言されたメソッドは暗黙のうちにpublicになるため、修飾子publicは省略可能です。
インターフェイス中に宣言された定数は暗黙のうちにpublic, static, finalになります。これらの修飾子は省略可能です。
インターフェイスを実装する
インターフェイスを型として使う
インターフェイスを書き換える
下記のインターフェイスがありました。
public interface NewInterface {
public void func1();
}
func2を追加したくなったけれど、NewInterfaceは既に多くのプロジェクトで使われていて、変更できない場合、
public interface NewInterface2 extends NewInterface {
public void func2();
}
とする事で、NewInterfaceを拡張したNewInterface2を作る事が出来ます。
インターフェイスのまとめ
インターフェイスにはシグネクチャが含まれるが、実装はない。
定数の定義を含めることは可能。
継承
継承チェーン中の最上位クラスはObjectである。
Javaプラットフォームのクラス階層
継承の例
サブクラスでできること
サブクラスは、パッケージに関係なく、親クラスのpublicとprotectedのメンバをすべて継承する。
スーパークラスと同一パッケージに属する場合は、親クラスのパッケージprivateなメンバも継承する。
スーパークラス中のprivateメンバ
サブクラスは、スーパークラスのprivateメンバにアクセス出来ません。
その為、privateフィールドにアクセスする為の、publicまたはprotectedのメソッドが、スーパークラスにて用意されていれば、サブクラスにて使用する事が可能。
オブジェクトのキャスト
// 暗黙のキャスト
Object obj1 = new SubClass();
// obj1をsubCls1に代入しようとした時は、
// ↓これだとコンパイルエラーが出るので
//SubClass subCls1 = obj1;
// 明示的なキャストを行う事でコンパイルエラーを回避する
SubClass subCls1 = (SubClass)obj1;
このキャストにより、obj1にsubCls1が代入されている事を確認する実行時チェックが挿入され、実行時にobj1がSubClassでなければ例外が投げられます。
// 明示的なキャストを行う事でコンパイルエラーを回避する
//SubClass subCls1 = (SubClass)obj1;
//
// ↑のコードの代わりに、↓みたくなる?
if(obj1 instanceof SubClass)
{
SubClass subCls1 = (SubClass)obj1;
}
else
{
// 例外を投げる
}
メソッドのオーバーライドと隠蔽
クラスメソッド
public class SuperClass {
public void nakigoe()
{
System.out.println("わん!");
}
}
public class SubClass extends SuperClass {
public SubClass(int red, int green, int blue)
{
System.out.println("にゃー!にゃー!");
}
}
SuperClassの場合は、nakigoe()を呼び出すと「わん!」と鳴きました。
SubClassの場合は、SuperClassのnakigoe()を隠蔽して、nakigoe()をオーバーライドしている為、「にゃー!にゃー!」と鳴くようになります。
修飾子
public class SuperClass {
protected void nakigoe()
{
System.out.println("わん!");
}
}
public class SubClass extends SuperClass {
// スーパークラスは、protected
public void nakigoe()
{
System.out.println("にゃー!にゃー!");
}
}
オーバーライドは「ゆるふわ」のみ許容しています。
つまり、スーパークラスのメソッドがprotectedの場合、サブクラスではpublicには出来ても、privateにする事が出来ません。
まとめ
フィールドの隠蔽
サブクラスにスーパークラスと同じ名前を持つフィールドが存在する場合、スーパークラス内のフィールドを隠蔽します。
一般的には、フィールドの隠蔽は可読性の問題から推奨出来ない。
キーワードsuper
スーパークラスのメンバーにアクセスする
public class SuperClass {
public void nakigoe()
{
System.out.println("わん!");
}
}
public class SubClass extends SuperClass {
public void nakigoe()
{
super.nakigoe();
System.out.println("にゃー!にゃー!");
}
}
キーワードsuperを使うことで、スーパークラスのnakidoeメソッド「わん!」を呼ぶ事が出来ます。
サブクラスのコンストラクタ
コンストラクタで明示的にスーパークラスのコンストラクタを呼び出さなかった場合、Javaコンパイラによって、引数無しのスーパークラスのコンストラクタを自動的に挿入されてしまいます。
また、継承をしまくるとObjectのコンストラクタへ至るコンストラクタ連鎖が行われる事を認識すること。
スーパークラスとしてのObject
clone
外部オブジェクトへの参照を持っているオブジェクトは、外部オブジェクトのクローンも生成する様にcloneオーバーライドする必要がある。
equals
(==)を使って2つのオブジェクトが等しいどうかを判断する。オブジェクト参照によって同一のオブジェクトかどうかを判断する。
finalize
ガベージコレクタによって呼び出される「可能性」があります。よって、そもそも呼び出されるかも不確定なので、後始末の処理をこのメソッドに頼ってはいけません。
getClass
オーバーライド出来ません。
hashCode
ハッシュを比較し、等価のオブジェクトであるか判断を行っているので、equalsをオーバーライドした場合は、hashCodeもオーバーライドする必要がある。
toString
オブジェクトの文字列表現を返す。クラスを作成した時は、必ずオーバーライドする事を検討すべきです。
finalクラスとfinalメソッド
クラス全体をfinalにする事も可能。コンストラクタから呼び出すメソッドは、一般的にfinalと宣言すべきです。
public class SuperClass {
protected final void nakigoe()
{
System.out.println("わん!");
}
}
nakigoeメソッドでfinal宣言している場合、
public class SubClass extends SuperClass {
public void nakigoe()
{
System.out.println("にゃー!にゃー!");
}
}
SuperClassを継承したSubClassで、nakigoeメソッドをオーバーライドする事が出来ません。
Stringクラスもクラス全体をサブクラス化を阻止しています。
抽象クラスと抽象メソッド
インターフェイス中のメソッドは、すべて暗黙的に抽象メソッドとして扱われる為、abstract宣言は必要無い。
public abstract class AbstractClass {
// 抽象メソッドは宣言だけ
abstract public void nakigoe();
// 普通にフィールド宣言を宣言する事が出来る
private int jumpCarry;
// 普通にメソッドの実装をする事も出来る
protected int getJumpCarry()
{
return jumpCarry;
}
}
public class SubAbstractClass extends AbstractClass {
// サブクラスでnakigoeメソッドを実装する
public void nakigoe()
{
System.out.println("くーん……くーん……");
}
}
抽象クラスとインターフェイス
インターフェイスと違い、抽象クラスはstatic、finalではないフィールドを保持出来ることと、メソッドの実装を含める事が出来ます。実装を共有するためにサブクラス化するのが一般的です。
抽象クラスの例
インターフェイスを実装する抽象クラス
abstract class X implements Y {
// Yの一部のメソッドを実装
}
class XX extends X {
// Yの残りのメソッドを実装
}
クラスメンバー
抽象クラスはstaticフィールドとstaticメソッドを持つことが出来る。
継承のまとめ
- 単一継承
- サブクラスでは継承したメソッドをオーバーライトしたり、隠蔽したりすることが出来る
- すべてのオブジェクトはObjectからメソッドを継承している
- finalを使うことでサブクラスでのオーバーライドを防ぐことが出来る
- 抽象クラスはインスタンス化出来ず、サブクラス化するだけ