JAvaマルチステートのメンバーバインド
3415 ワード
マルチステートはオブジェクト向けの三大特徴の一つであるマルチステートについて言及しなければならないのは、マルチステートにおけるメンバーバインド問題である.
メソッドバインド
1つのメソッド呼び出しを同一のメソッド本体に関連付けることをバインディングと呼ぶ.プログラム実行前にバインド(ある場合はコンパイラと接続プログラムで実現)を行う場合を前期バインドと呼ぶ.実行時にオブジェクトの種類に応じてバインドする、後期バインドと呼ばれ、動的バインドまたは実行時バインドとも呼ばれる.
Javaではstaticメソッドとfinalメソッド(privateメソッドはfinalメソッドに属する)を除いて、他のすべてのメソッドは後期バインドである.
欠陥:Privateメソッドの上書き
我々が望む出力はpublic f()であるが、private法はfinal法と自動的に認識され、導出クラス(サブクラス)に対して遮蔽.したがって、この場合、Derivedクラスのf()メソッドは、ベースクラスのf()メソッドがサブクラスのDerivedでは見えないため、リロードすることさえできない新しいメソッドである.
欠陥:ドメインと静的メソッド
ドメインに直接アクセスすると、次の例で示すように、コンパイル期間中にこのアクセスが解析されます.
SubオブジェクトがSuperリファレンスに移行すると、どのドメインアクセス操作もコンパイラによって解析するので、マルチステートではない.本例では、Super.fieldとSub.fieldは異なる記憶空間を割り当てる.このように、Subは実際にはfieldと呼ばれる2つのドメインを含む:それ自身とそれはSuperから得たものである.しかし、Subのfieldを参照するときに生じるデフォルトドメインは、Superバージョンのfieldドメインではない.
方法が静的である場合、その動作には多態性はありません.
メソッドバインド
1つのメソッド呼び出しを同一のメソッド本体に関連付けることをバインディングと呼ぶ.プログラム実行前にバインド(ある場合はコンパイラと接続プログラムで実現)を行う場合を前期バインドと呼ぶ.実行時にオブジェクトの種類に応じてバインドする、後期バインドと呼ばれ、動的バインドまたは実行時バインドとも呼ばれる.
Javaではstaticメソッドとfinalメソッド(privateメソッドはfinalメソッドに属する)を除いて、他のすべてのメソッドは後期バインドである.
public class Shape {
public void draw() {
System.out.println("Shape draw.");
}
public void erase() {
System.out.println("Shape erase");
}
}
public class Circle extends Shape {
public void draw() {
System.out.println("Circle draw.");
}
public void erase() {
System.out.println("Circle erase.");
}
}
public class Shapes {
public static void main(String[] args) {
Shape shape = new Circle();
shape.draw();
}
}
//output
Circle draw.
欠陥:Privateメソッドの上書き
public class PrivateOverride {
private void f(){
System.out.println("private f()");
}
public static void main(String[] args){
PrivateOverride privateOverride = new Derived();
privateOverride.f();
}
}
class Derived extends PrivateOverride{
public void f(){
System.out.println("public f()");
}
}
//output
private f()
我々が望む出力はpublic f()であるが、private法はfinal法と自動的に認識され、導出クラス(サブクラス)に対して遮蔽.したがって、この場合、Derivedクラスのf()メソッドは、ベースクラスのf()メソッドがサブクラスのDerivedでは見えないため、リロードすることさえできない新しいメソッドである.
欠陥:ドメインと静的メソッド
ドメインに直接アクセスすると、次の例で示すように、コンパイル期間中にこのアクセスが解析されます.
class Super {
public int field = 0;
public int getField() {
return field;
}
}
class Sub extends Super {
public int field = 1;
public int getField() {
return field;
}
public int getSuperField() {
return super.field;
}
}
public class FieldAccess {
public static void main(String[] args) {
Super sup = new Sub();
System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField());
Sub sub = new Sub();
System.out.println("sub.field = " + sub.field + ", sub.getField() = " + sub.getField());
System.out.println("sub.getSuperField() = " + sub.getSuperField());
}
}
//output
sup.field = 0, sup.getField() = 1
sub.field = 1, sub.getField() = 1
sub.getSuperField() = 0
SubオブジェクトがSuperリファレンスに移行すると、どのドメインアクセス操作もコンパイラによって解析するので、マルチステートではない.本例では、Super.fieldとSub.fieldは異なる記憶空間を割り当てる.このように、Subは実際にはfieldと呼ばれる2つのドメインを含む:それ自身とそれはSuperから得たものである.しかし、Subのfieldを参照するときに生じるデフォルトドメインは、Superバージョンのfieldドメインではない.
方法が静的である場合、その動作には多態性はありません.
class StaticSuper {
public static String staticGet() {
return "Base staticGet()";
}
public String dynamicGet() {
return "Base dynamicGet()";
}
}
class StaticSub extends StaticSuper {
public static String staticGet() {
return "Derived staticGet()";
}
public String dynamicGet() {
return "Derived dynamicGet()";
}
}
public class StaticPolymorphism {
public static void main(String[] args) {
StaticSuper sup = new StaticSub();
System.out.println(sup.staticGet());
System.out.println(sup.dynamicGet());
}
}
//outp
Base staticGet()
Derived dynamicGet()