[Java] オーバーロード、継承とオーバーライドと可視性

phpと比較しつつ…といってもphpが微妙にうろ覚えで違ってないか不安

メソッドのオーバーロード

phpのオーバーロードとは意味が全く違う(phpが特殊なだけ、アクセス不可メンバにアクセスした時に起動する特殊メソッド)

Javaのオーバーロードは 同じ識別子のメソッドでも引数の型・数・順番(仮引数の識別子は関係なし)が異なれば違う内容のメソッドを多重定義できるという意味。

public class Over {
  public static void main(String[] args) {
    Over.ride(777);
    Over.ride();
  }

  public static void ride(int n) {
    System.out.println("固定引数");
  }

  public static void ride(int... n) {
    int sum = 0;
    for (int i = 0; i < n.length; i++) {
      sum += n[i];
    }
    System.out.println("可変引数");
  }
}

結果

固定引数
可変引数

可変長引数より固定長引数をもつメソッドが優先される

クラスの継承

親クラスをスーパークラス、子クラスをサブクラスと呼ぶ。phpでも同じ用語をつかうっぽいんだけど知らなかった。 extends の使い方は php と多分同じ。多重継承はできない。

class A extends B {}
class B extends C {}
class C{}

public class\ D extends A, B // コンパイルエラー

メソッドの継承と可視性

↓準備

package net.fernwelt;

public class P {
  private void   pri() { System.out.println("Ppri"); }
  protected void pro() { System.out.println("Ppro"); }
  public void    pub() { System.out.println("Ppub"); }
}

継承したメソッドのコール

以下のソースでコンパイルエラーとなるのは何箇所?

package jp.fernweh;

import net.fernwelt.P;

public class C extends P {
  public static void main(String[] args) {
    C c = new C();
    c.pri();
    c.pro();
    c.pub();

    P p = new P();
    p.pri();
    p.pro();
    p.pub();
  }
}

3箇所だね。

メソッドのオーバーライドと可視性

以下のコードでコンパイルエラーになるのは何箇所?

その部分をコメントアウトするとどう出力される?

package jp.fernweh;

import net.fernwelt.P;

public class C extends P {

  private void   pri() { System.out.println("Cpri"); }
  protected void pro() { System.out.println("Cpro"); }
  public void    pub() { System.out.println("Cpub"); }

  public void callP() {
    super.pri();
    super.pro();
    super.pub();
  }

  public static void main(String[] args) {
    C c = new C();
    c.pri();
    c.pro();
    c.pub();
    System.out.println();

    c.callP();
    System.out.println();

    P p = new P();
    p.pri();
    p.pro();
    p.pub();
  }
}

コンパイルエラーになるのは3箇所で、 エラー部分をコメントアウトして実行すると イカの様に出力される。

結果

Cpri
Cpro
Cpub

Ppro
Ppub

Ppub

また、PHPと同様にメソッドをオーバーライドするときに可視性を下げることはできない。

class C extends B {
  public void pri() {}
  private void pro() {} // コンパイルエラー
  protected void pub() {} // コンパイルエラー
}

class B {
  private void pri() {}
  protected void pro() {}
  public void pub() {}
}

フィールドの継承と可視性

継承したフィールドへのアクセス

以下のコードでエラーとなるのはどこ?

その部分をコメントアウトするとどのように出力される?

package net.fernwelt;

public class P {
  private String pri = "Ppri";
  protected String pro = "Ppro";
  public String pub = "Ppub";

  public void printP() {
    System.out.println(this.pri);
    System.out.println(this.pro);
    System.out.println(this.pub);
    System.out.println();
  }
}
package jp.fernweh;

import net.fernwelt.P;

public class C extends P {

  public static void main(String[] args) {
    C c = new C();
    System.out.println(c.pri);
    System.out.println(c.pro);
    System.out.println(c.pub);

    P p = new P();
    System.out.println(p.pri);
    System.out.println(p.pro);
    System.out.println(p.pub);
    System.out.println();

    p.printP();

    c.printC();
    c.printP();
  }

  public void printC() {
    System.out.println(this.pri);
    System.out.println(this.pro);
    System.out.println(this.pub);
    System.out.println(super.pri);
    System.out.println(super.pro);
    System.out.println(super.pub);
    System.out.println();
  }

}

5箇所でコンパイルエラーとなり、

その部分をコメントアウトすると以下のようになる

結果

Ppro
Ppub
Ppub

Ppri
Ppro
Ppub

Ppro
Ppub
Ppro
Ppub

Ppri
Ppro
Ppub
  • 別パッケージのprotected フィールドには直接アクセスできない
  • protectedフィールドは継承すればそのクラスで自由に使用できる
  • 継承したクラスのprivateフィールドはスーパークラスのメソッドを介してアクセスできる。

phpの継承とかなり違うので超混乱。phpではプロパティをオーバーライドすると親クラスのprotected, public プロパティは消滅する。そもそも継承したクラスのプロパティにアクセスするsuper()みたいなものが存在しない。phpでのプロパティ継承のイメージは遺産を受け取る感覚(なんだそれ)だけど、Javaでは親クラスのメンバにアクセスできる権利をもらえるだけな感じ?

フィールドのオーバーライドと可視性

以下のコードでコンパイルエラーとなるのはどこ?

その部分をコメントアウトするとどのように出力される?

package net.fernwelt;

public class P {
  private String pri = "Ppri";
  protected String pro = "Ppro";
  public String pub = "Ppub";
}
package jp.fernweh;

import net.fernwelt.P;

public class C extends P {

  private String pri = "Cpri";
  protected String pro = "Cpro";
  public String pub = "Cpub";

  public static void main(String[] args) {
    C c = new C();
    System.out.println(c.pri);
    System.out.println(c.pro);
    System.out.println(c.pub);

    P p = new P();
    System.out.println(p.pri);
    System.out.println(p.pro);
    System.out.println(p.pub);
    System.out.println();

    c.printC();
  }

  public void printC() {
    System.out.println(this.pri);
    System.out.println(this.pro);
    System.out.println(this.pub);
    System.out.println(super.pri);
    System.out.println(super.pro);
    System.out.println(super.pub);
  }

}

3箇所でコンパイルエラーとなり、 その部分をコメントアウトすると以下のようになる

結果

Cpri
Cpro
Cpub
Ppub

Cpri
Cpro
Cpub
Ppro
Ppub

フィールドのオーバーライドでの可視性の変更

メソッドとは違ってフィールド継承により可視性が変化しても問題ない。 まぁ基本的にはprivateフィールドを使うのであまり意識することはなさそうだけども。

Wordpress運用時のコメントログ

Aki Sen 1209 より: 2012年7月3日 12:16 PM

phpではプロパティを継承すると親クラスのprotected, public プロパティは消滅する。そもそも継承したクラスのプロパティにアクセスするsuper()みたいなものが存在しない。phpでのプロパティ継承のイメージ は遺産を受け取る感覚(なんだそれ)だけど、Javaでは親クラスのメンバにアクセスできる権利をもらえるだけな感じ?

PHPでも継承しただけではスーパークラスのメンバは消滅しませんよ。 プロパティ(フィールド)に限って言えば、サブクラスでオーバーライドした時点で スーパークラスのプロパティは消滅します。 メソッドに関して言えば、オーバーライドしてもJAVAでいうsuperキーワードに準じたparentがあるので厳密に言えば消滅はしません。

プロパティだけオーバーライドした場合のみ例外的に消滅する感じですね。

Fernweh より: 2012年7月22日 8:54 AM

コメントありがとうございます。

たしかに継承してプロパティが消滅したらトンデモナイですね orz

修正しました。 教えてくれてありがとうございます!

Fernweh より: 2012年8月28日 12:50 AM

てかフィールドのオーバーライドなんてJavaではできなくて隠蔽だよな orz この記事書いてた頃はまだまだ分からんことばっかだったな…今でも分からんことばっかだけど。

Share
関連記事