第 2 章 Java 言語の基本的な文法 I 5
3.4 インヘリタンス ( 継承 )
3.4.3 オーバーライド
一般に、スーパークラスをサブクラスが継承するときは、新たなフィールドやメソッドを追加することが多いのです が、スーパークラスで既に存在するメソッドを書き換えたい、という場合もあります。以下のプログラムでは、ソース コード3.32で作成したWeightedPointクラスを継承したColoredWeightedPointクラスを作成し、スーパークラ スのWeightedPointクラスの持っていたprint()メソッドを色付き点用に書き換えています。
ソースコード3.37 PointExample4.tex (メソッドをオーバーライド) package section0304;
import javafx.scene.paint.Color; // javafx.scene.paint パッケージにある Color クラスを使用 public class PointExample4 {
public static void main(String[] args) {
ColoredWeightedPoint p = new ColoredWeightedPoint(1.0, 2.0, 3.0, Color.RED );
p.print();
} }
ソースコード3.38 ColoredWeightedPoint.java (色付き重み付き点クラス) package section0304;
import javafx.scene.paint.Color;
public class ColoredWeightedPoint extends WeightedPoint { private Color color;
public ColoredWeightedPoint( double x, double y, double w, Color color ) { super( x, y, w );
this.color = color;
}
@Override
public void print() {
System.out.printf( "(%f, %f), w=%f:c=%s%n", this.getX(), this.getY(), this.getWeight(), this.color.toString() );
} }
こ の と き 、p.print(); と 言 う 命 令 で 、ColoredWeightedPoint ク ラ ス の メ ソ ッ ド print() と そ の ス ー パ ー ク ラ ス の WeightedPoint ク ラ ス の メ ソ ッ ド print() の ど ち ら が 使 わ れ る で し ょ う か ? た ぶ ん 直 感 通 り 、 ColoredWeightedPointクラスの方ですよね。
スーパークラスとサブクラスで引数の個数と型が一致した同じ名前のメソッドが存在する場合をメソッドの「オー バーライド」と言って、いわゆる再定義・重ね書きが行われます。
ちょっと複雑になってきましたが、平面上の3 種類の点のクラスのUML でのクラス図を以下に書いておきます。
下線の引かれたメソッドはクラスメソッドです。print() メソッドがいずれのクラスにも定義されていますね。オー バーライドで書き換わっているわけです。
Point - x : double
- y : double
- ORIGIN : Point {final}
+ setX( x : double ) : void + setY( y : double ) : void + getX( ) : double + getY( ) : double + print( ) : void + length( ) : double + distance( p : Point ) : double + distance( p : Point, q : Point ) : double + centroid( p : Point, q : Point ) : Point
<<constructor>>
+ Point( x : double, y : double )
WeightedPoint
- weight : double + getWeight() : double + print( ) : void
+ centroid( WeightedPoint ) : WeightedPoint
<<constructor>>
+ WeightedPoint( x : double, y : double, w : double ) + WeightedPoint( p : WeightedPoint )
ColoredWeightedPoint
- color : javafx.scene.paint.Color + print( ) : void
<<constructor>>
+ ColoredWeightedPoint( x : double, y : double, w : double, color : Color ) + public
# protected
~ package private - private
可視性
図3.7 オーバーライドをUMLで
なお、プログラム中9行目の@Overrideは、以前も出てきましたが、「アノテーション」です。コンパイラにこのメ ソッドがスーパークラスのメソッドのオーバーライドであることを教える機能です。付けなくてもエラーにはなりませ んが、付けるクセを付けておきましょう。
メソッドをオーバーライドさせる場合、アクセス権を変えてはいけないのでしょうか?次のプログラムを作ってみる と、SubClassのmethod()に文法エラーが発生します。
ソースコード3.39 OverrideExample2.java (オーバーライドにおけるアクセス権) package section0304;
public class OverrideExample2 {
public static void main(String[] args) { SubClass a = new SubClass();
a.method();
} }
// スーパークラス class SuperClass {
public void method() {
System.out.println( "SuperClass.method()" );
} }
// サブクラス
class SubClass extends SuperClass {
@Override void method() {
System.out.println( "SubClass.method()" );
} }
これは、スーパークラスではpublic が付いていたメソッドをpackage-privateにアクセス権を厳しくしたからです。
これを逆にしてみると (スーパークラス側をpackage-privateにして、サブクラス側をpublic にすると)エラーは起 きません。つまり、オーバーライドするとき、アクセス権は同等かより緩いものにしなければいけません。これは、サ ブクラスではスーパークラスの全てのことが行える環境になければいけないわけで、勝手に厳しくしてはいけない!と いうことですね。
例えば、ObjectクラスのtoString()やequals()メソッドはpublicに定義されており、clone()はprotected に設定されていますので、自分のクラスでオーバーライドする際は、それらを踏襲しなければいけません。ハッシュ コードなんかが出力されるtoString() メソッドを自分のクラスにフィットしたメソッドにオーバーライドすること はよく行われます。逆に、これらのメソッドをそのままにしておくと、外部からこれらのメソッドをオーバーライドし てクラスの情報を盗み見られる!ということもありです。Objectクラスのメソッドは常に気を付けていなければいけ ません (この授業では気にかけていませんがね)。
問題 3.4.6. 先に作ったPoint クラス、および、そのサブクラスにおいて、 toString() メソッドをそれぞれオー バーライドし、Pointクラスの print()メソッドはtoStringによる文字列を出力するメソッドとして表し、サブク
ラス側の print()メソッドをいずれも削除しなさい。
問題 3.4.7. 以下のプログラム構成での5つの出力文がコンパイルエラーになるか、ならないかを述べよ。
package p1;
import p2.B;
public class C {
public static void main(String[] args) { A a = new A();
a.method();
System.out.println( a.x );
System.out.println( a.b[0] );
System.out.println( a.y );
System.out.println( a.z );
} }
class A extends B { public int x = 100;
int[] b = {1,2,3};
void method() { A a = new A();
System.out.println( a.z );
} }
package p2;
public class B {
private int y = 123;
protected double z = 1.23;
}