スタートページJavascriptJava

Javaシリーズの目次

Javaの文法(6) オーバーロード、オーバーライド


概念

オブジェクト指向において、オブジェクト(クラス)の重要な概念として、継承(インヘリタンス)と多様化(ポリモーフィズム)があります。

継承 スーパークラス/サブクラス

自動車には乗用車、トラックなどの種類がありますが、どの種類でも、名称、メーカー、排気量など共通する属性があります。また、乗用車には、乗車定員やチャイルドシート数、トラックでは荷台面積や最大積載容量など独自の属性があります。

このような全体-部分の関係があるとき、自動車全般の共通する事項を定義するクラスをスーパークラスといい、乗用車やトラックなど、部分を対象とし、独自の事項を定義するクラスをサブクラスといいます。
そして、サブクラスがスーパークラスの定義を引き継ぐことを継承(インヘリタンス)といいます。

多様化

例えば、整数配列の合計を求めるメソッドを sumInt(整数配列)、実数配列の合計を求めるメソッドを sumFloat(実数配列) などと個別のメソッドにするのではなく、どのような型であっても一つのメソッド sum(配列) とできれば便利です。
また、ファールとは、野球であればストライクが1つ増えることであり、サッカーであれば相手側のボールになる(厳密ではない)ことだとすれば、同じメソッドでも機能が異なります。
このように同じメソッド名でも、(呼び出し側での)状況により、異なる処理をする仕組みを多様化(ポリモーフィズム)といいます。

オーバーライド、オーバーロード

継承・多様化の機能を Java で記述するには、オーバーライド、オーバーロードがあります。
大雑把には、オーバーライド = 継承、オーバーロード = 多様化 ですが厳密ではありません。異なる機能に使われることもあります。

オーバーライド:親クラスにあるメソッドを子クラスで再定義することによって、子クラス上で親クラスのメソッドを上書きすること
  一般に、スーパーメソッドは引数なし、サブメソッドは引数ありで、引数の個数と型指定によりブクラスが一意に定まります。
  (同じ引数個数、型指定で異なるサブクラスを設定することはできません。)

オーバーロード:引数の数とか型とかが違う、同じ名前の関数を複数個、用意すること


継承

変数の継承

「学生」をスーパークラス、「学生」のうちの「留学生」をサブクラスとします。
Javaでは、スーパークラスで定義されたことをサブクラスで再度定義することをオーバーライドといいます。留学生クラスは学生クラスをオーバーライドです。
サブクラス次のように記述します。
  class サブクラス名 extends スーパークラス名

class 学生クラス {                          // スーパークラス
  String 氏名 = "阿部";                        // スーパークラスの構造体とその値
  String 学部 = "文学部";
  int 年齢 = 20;
};
                                       // これがオーバーライド
class 留学生クラス extends 学生クラス {    // サブクラス (extends でスーパークラスを指定)
  String 国籍 = "米国";                        // 新規の要素
  String 氏名 = "Smith";                       // スーパークラスの変更
};                                             // ここで指定しないものはスーパークラスで指定した値を継承

public class Main {
  public static void main(String[] args) {
    学生クラス 学生 = new 学生クラス();        // スーパークラスの構造体
    System.out.println("学生:"                             // 学生:阿部, 文学部. 20
      + 学生.氏名 + ", " + 学生.学部 + ". " + 学生.年齢);
    留学生クラス 留学生 = new 留学生クラス();  // サブクラスの構造体
    System.out.println("留学生:"                           // 留学生:Smith, 文学部. 20, 米国
      + 留学生.氏名 + ", " + 留学生.学部 + ". " + 留学生.年齢 + ", " + 留学生.国籍);
  }
}

処理の継承

ここでは、ある倉庫の在庫管理のうち、在庫減に関する部分を例にします。
倉庫から商品が出ることを「出荷」、そのうち、客先に出荷することを「売上」、社内の別倉庫に転送することを「転送」ということにします。
出荷はスーパークラス、売上と転送はサブクラスの関係があります。

mainメソッドから出荷量が受け渡されたとき、
  出荷で共通メソッドである「在庫量 = 在庫量 - 出荷量」と「出荷量 > 在庫量 でのエラー処理」をします。
  売上では「売上量 = 出荷量」の処理をするだけでよいし、転送では「何もしない」でよいことになります。
の処理になります。

class 出荷 {
  int 在庫量 = 10;
  int 売上量 = 0;
  int 出荷量 = 0;
  public 出荷(int 出荷量) {
    this.出荷量 = 出荷量;
    在庫量 = 在庫量 - 出荷量;
    if (在庫量 < 0) {
      System.out.println("エラー! 出荷量 > 在庫量");
      System.exit(0);
    }
  }
}
class 売上 extends 出荷 {
  public 売上(int 出荷量) {
    super(出荷量);           // 出荷量に関するスーパークラスの処理を継承
    this.出荷量 = 出荷量;
    売上量 = 出荷量;
  }
}
class 転送 extends 出荷 {
	public 転送(int 出荷量) {
	    super(出荷量);
	    this.出荷量 = 出荷量;
	}
}
public class Main {
  public static void main(String[] args) {
    売上 売上結果 = new 売上(3);
    System.out.println("売上:出荷量=" + 売上結果.出荷量    // 売上:出荷量=3, 在庫量=7, 売上量=3
       + ", 在庫量=" + 売上結果.在庫量 + ", 売上量=" + 売上結果.売上量); 
    転送 転送結果 = new 転送(4);
    System.out.println("転送:出荷量=" + 転送結果.出荷量    // 転送:出荷量=4, 在庫量=6, 売上量=0
       + ", 在庫量=" + 転送結果.在庫量 + ", 売上量=" + 転送結果.売上量);
  }
}

多様化

多様化(型指定による)

整数での合計、実数での合計を、引数の型指定により同じメソッド名で使えるようにします。

class 合計クラス {
    public int 合計(int a, int b) {
        return a + b;
    }
    public double 合計(double a, double b) {   // 上と同じメソッド名 オーバーロード
        return a + b;
    }
}

public class Main {
    public static void main(String[] args) {
        合計クラス 結果 = new 合計クラス();
        System.out.println("整数:" + 結果.合計( 1, 2));      // 3
        System.out.println("実数:" + 結果.合計( 1.3, 2.5));  // 3.8
    }
}

多様化 (引数個数)

class 学生クラス {
  String 氏名;
  int 年齢;

  public 学生クラス() {                      // パラメタなし。氏名・年齢は省略値
    this.氏名 = "阿部";      // this とは「ここでの」のような意味。阿部に固定
    this.年齢 = 20;
  };

  public 学生クラス(String 氏名, int 年齢) {  // 同じコンストラクタ名。パラメタあり。氏名・年齢は Mainで与える
    this.氏名 = 氏名;        // this は引数、すなわち Main で与えた値にすることを示す。
    this.年齢 = 年齢;
  };
}
public class Main {
  public static void main(String[] args) {
    学生クラス 学生1 = new 学生クラス();
    System.out.println(学生1.氏名 + ", " + 学生1.年齢); // 阿部, 20
    学生クラス 学生2 = new 学生クラス("井上", 21);
    System.out.println(学生2.氏名 + ", " + 学生2.年齢); // 井上, 21
  }
}

多様化 (抽象クラスとオーバーライド)

整数での四則演算(ここでは加算と乗算だけ)を例にします。
   加算.計算(4, 2);    乗算.計算(4, 2)); のように「計算」メソッドを多様化しています。

// 抽象クラス
abstract class 四則演算 {
    public int 計算(int x, int y) {
        return 演算(x, y);
    }
    abstract protected int 演算(int x, int y);
}

// 加算クラス(サブクラス)
class 加算 extends 四則演算 {
    @Override
    protected int 演算(int x, int y) { return (x+y); }
}

// 乗算クラス(サブクラス)」
class 乗算 extends 四則演算 {
    @Override
    protected int 演算(int x, int y) { return (x*y); }
} 

// プログラムの実行]
public class Main {
    public static void main(String[] args) {
        // 加算クラスの実行
        四則演算 加算 = new 加算();
        int 結果 = 加算.計算(4, 2);
        System.out.println(結果);
        
        // 乗算クラスの実行
        四則演算 乗算 = new 乗算();
        System.out.println(乗算.計算(4, 2));
    }
}