web-dev-qa-db-ja.com

静的メソッドからスーパーメソッドを呼び出す

子静的メソッドからスーパー静的メソッドを呼び出すことは可能ですか?

つまり、一般的な意味で、これまでのところ、私は次のものを持っています:

public class BaseController extends Controller {
    static void init() {
        //init stuff
    }
}

public class ChildController extends BaseController {
    static void init() {
        BaseController.loadState();
        // more init stuff
    }

}

そしてそれは機能しますが、私はそれが機能していないように見えるsuper.loadState()を呼び出すようなもののような一般的な方法でそれをしたいと思います...

23
opensas

Javaでは、静的メソッドをオーバーライドできません。その理由はきちんと説明されています here

したがって、参照されているオブジェクトには依存しません。しかし代わりに、それは参照のタイプに依存します。したがって、静的メソッドは別の静的メソッドを非表示にし、オーバーライドしないと言われています。

たとえば(CatはAnimalのサブクラスです):

public class Animal {
    public static void hide() {
        System.out.format("The hide method in Animal.%n");
    }
    public void override() {
        System.out.format("The override method in Animal.%n");
    }
}

public class Cat extends Animal {
    public static void hide() {
        System.out.format("The hide method in Cat.%n");
    }
    public void override() {
        System.out.format("The override method in Cat.%n");
    }
}

メインクラス:

public static void main(String[] args) {
    Cat myCat = new Cat();
    System.out.println("Create a Cat instance ...");
    myCat.hide(); 
    Cat.hide();
    myCat.override();  

    Animal myAnimal = myCat;
    System.out.println("\nCast the Cat instance to Animal...");
    Animal.hide();     
    myAnimal.override();

    Animal myAnimal1 = new Animal();
    System.out.println("\nCreate an Animal instance....");
    Animal.hide();     
    myAnimal.override();
}

今、出力は以下のようになります

Create a Cat instance ...
The hide method in Cat.
The hide method in Cat.
The override method in Cat.  

Cast the Cat instance to Animal...
The hide method in Animal.
The override method in Cat.

Create an Animal instance....
The hide method in Animal.
The override method in Animal.

ために class methods、ランタイムシステムは、メソッドが呼び出される参照のコンパイル時の型で定義されたメソッドを呼び出します。

つまり、静的メソッドの呼び出しはコンパイル時にマッピングされ、参照の宣言された型(この場合は親)に依存し、実行時に参照が指すインスタンスには依存しません。この例では、myAnimalのコンパイル時の型はAnimalです。したがって、ランタイムシステムはAnimalで定義された非表示メソッドを呼び出します。

17
sgokhales

Javaにはis静的継承があります。 Nikitaの例を採用する:

class A {
    static void test() {
        System.out.print("A");
    }
}
class B extends A {
}

class C extends B {
    static void test() {
        System.out.print("C");
        B.test();
    }

    public static void main(String[] ignored) {
       C.test();
    }
}

これはコンパイルされ、Cを呼び出すともちろん "CA"が出力されます。クラスBを次のように変更します。

class B extends A {
    static void test() {
        System.out.print("B");
    }
}

b(Cではなく)のみを再コンパイルします。ここで再びCを呼び出すと、「CB」が出力されます。

ただし、静的メソッドにはsuperのようなキーワードはありません。「(悪い)正当化は、「スーパークラスの名前がこのクラスの宣言に記述されているため、クラスを再コンパイルする必要があったためです。変更するので、ここでも静的呼び出しを変更できます。」

6
Paŭlo Ebermann

継承の概念全体は、Javaの静的要素には適用されません。たとえば、静的メソッドは別の静的メソッドをオーバーライドできません。
そのため、いいえ、名前で呼び出すか、オブジェクトのインスタンスメソッドにする必要があります。 (特に、ファクトリパターンの1つをチェックアウトすることをお勧めします)。

実用的な例

class A {
    static void test() {
        System.out.println("A");
    }
}
class B extends A {
    static void test() {
        System.out.println("B");
    }
}

    A a = new B();
    B b = new B();
    a.test();
    b.test();

これはAを出力し、次にBを出力します。つまり、呼び出されるメソッドは、変数がどのように宣言されているかによって異なります。

4
Nikita Rybak

メソッド名とそのパラメーターがわかっていれば、スーパークラスの静的メソッドを一般的な方法で実際に呼び出すことができます。

public class StaticTest {

    public static void main(String[] args) {
        NewClass.helloWorld();
    }    
}

public class NewClass extends BaseClass {
    public static void helloWorld() {
        try {
            NewClass.class.getSuperclass().getMethod("helloWorld", new Class[] {}).invoke( NewClass.class ,new Object[]{} );
        } catch (Exception e) {
            e.printStackTrace();
        } 

        System.out.println("myVar = " + myVar);
    }
}

public class BaseClass extends BaseBaseClass {
    protected static String myVar;
    public static void helloWorld() {
        System.out.println("Hello from Base");
        myVar = "Good";
    }
}

これは機能するはずであり、サブクラスでは、使用可能な基本クラスにすべてが設定されています。

出力は次のようになります。

ベースからこんにちは

myVar =良い

2
StefaX

実装の正式名称は method hiding と呼ばれます。静的なinit(Controller controller)メソッドを導入し、インスタンスメソッドを呼び出してオーバーライドを利用することをお勧めします。

public class Controller {
   static void init(Controller controller) {
      controller.init();
   }

   void init() {
      //init stuff
   }
}

public class BaseController extends Controller {

   @override
   void init() {
      super.init();
      //base controller init stuff
   }

}

public class ChildController extends BaseController {
   @override
   void init() {
      super.init();
      //child controller init stuff
   }
}

その後、Controller.init(controllerInstance)を呼び出すことができます。

1
BBb

静的メソッドの場合、クラスのインスタンスは必要ないため、スーパーはありません。

0
James