Java Silver 6章 クラスの継承とポリモフィズム


継承

既存のクラスをもとに新しいクラスを定義する
継承元のクラスをスーパークラス、新たに定義されたクラスをサブクラスと呼ぶ

継承の役割:差分プログラミング
複数のクラスに共通する処理をスーパークラスに定義し、各クラスで実装したい機能をサブクラスで定義する。

スーパークラスから継承するもの
・変数(フィールド)
・メソッド

継承しないもの
・コンストラクタ
・privateな変数(フィールド)、メソッド

抽象クラス

クラスを作成する際、その骨組みにあたるクラスを抽象クラス(abstractクラス)と呼ぶ
抽象クラスには処理内容を記述しない抽象メソッド(abstractメソッド)を作成可能
また普通のメソッドと抽象メソッドを混在して使用可能である

【アクセス修飾子】abstract class クラス名{}
【アクセス修飾子】abstract 戻り値 メソッド名 (引数);

抽象クラスのルール
・抽象クラスはインスタンス化できず、継承したサブクラスを作成しインスタンス化する
・抽象クラスを継承したサブクラスは、抽象クラスの抽象メソッドを全てオーバーライドする必要がある
・抽象クラスを継承した抽象クラスは、元となる抽象クラスの抽象メソッドのオーバーライドは任意

// 抽象クラス
abstract class User{
  //具象メソッド:オーバーライドは任意
  public void sayHo(){
    System.out.println("HO");
  }

  //抽象メソッド:オーバーライドは必須
  public abstract void sayHi();
}

// 具象クラス
class JapaneseUser extends User{
  @Override //オーバーライド
  public void sayHi(){
    System.out.println("こんにちは");
  }
}

class AmericanUser extends User{
  @Override
  public void sayHi(){
    System.out.println("Hi");
  }

}

public class Sample{

  public static void main(String[] args) {
    JapaneseUser taro = new JapaneseUser();
    AmericanUser tom = new AmericanUser();

    taro.sayHi();
    taro.sayHo();
    tom.sayHi();

  }
}

インターフェース

クラスを作成する際に公開すべき必要なメソッドと定数を定義するクラスの取り決め
抽象メソッド、デフォルトメソッド、staticな定数(final)のみ宣言できる

【アクセス修飾子】interface インターフェース名{}
【アクセス修飾子】defoult 戻り値 メソッド名(引数){}

インターフェースのルール
・インターフェースに宣言できる変数(フィールド)はstatic、もしくは定数のみ
・アクセス修飾子がないと強制的にpublic static finalとなる
・メソッドはデフォルトと抽象クラスが宣言可能

抽象クラスとインターフェースの違い

どちらもクラス作成のもととなる

抽象クラス:クラスの「骨組み」、共通処理を定める
インターフェース:クラスの「型」、扱い方を決める情報を定める

上の図では内側になるほど基底、外側になるほど継承となる

インターフェースは複数のクラスが継承できる特徴がある
便利な面もあるが、あるクラスの仕様変更が及ぼす影響が複雑となるデメリットがある

インターフェースの概念が特にわかりずらい
例として「3」について、
int型の整数3と、floot型の浮動小数点数3.00のように型が違うと扱いも異なるが種類としては数字である。
同様にクラスにも型を定め扱い方を明言する際インターフェースを使用する
そのためpublicで公開しstaticで共通の変数やメソッドを宣言している

//interface

interface Printable{
  //定数
  double VERSION = 1.2;

  //抽象メソッド
  void print();

  //defaultメソッド
  public default void getInfo(){
    System.out.println("I/F ver. " + Printable.VERSION);
  }
  //staticメソッド

}

class User implements Printable{
  //インターフェースをもとに実装クラスを作成

  //抽象メソッドは必ずオーバーライド
  @Override
  public void print(){
    System.out.println(
      "Now printing user profile...");
  }
}

public class Sample {

  public static void main(String[] args){
    User tom = new User();
    tom.print();

    //defaultメソッドは実装クラスに共通したメソッドとして使用可能
    tom.getInfo();
  }

}

interfaceof演算子

参照変数名 innterfaceof クラス名・インスタンス名

インターフェースとクラス、インスタンスの継承関係の有無をboolen値で返す

interface A { }
class B { }
class C extends B { }
class D { }
public class Main {
  public static void main(String[] args) {
    C obj = new C();
    System.out.println(obj instanceof A);
    System.out.println(obj instanceof B);
    System.out.println(obj instanceof C);
    //System.out.println(obj instanceof D); 継承なしはコンパイルエラー
  }
}
n
false
true
true