8
<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test(); // Outputs "B"
?>

我想在Java中得到一个等价物......所以像

class A {
    public static void who(){
        System.out.println("A");
    };

    public static void test(){
        who(); //<<< How to implement a static:: thing here???
    }
}

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

     public static void main(String[] args){
        B.test(); // Outputs "A" but I want "B"
     }
}

我希望who()内部A::test调用通过调用B::who.

编辑:我知道在最流行的语言中没有这样做的“标准方式”。我正在寻找黑客等。此外,这在 C/C++ 或任何其他流行的 OOP 语言中是否可行?

这不适用于任何真正的设计。我只是好奇。

4

5 回答 5

2

在 Java 中是不可能的。(至少不是没有丑陋的反射黑客。)

我鼓励您重新考虑您的设计并依赖适当的对象。

相关问题:

编辑: B.test()将(或至少根据规范)编译为对 的调用A.test(),因此无法发现调用是如何从A.test(). 换句话说,没有办法让 的行为A.test依赖于它是否通过A.test()or调用B.test()

由于您是出于好奇而询问,因此这是 AFAIK 最接近的“解决方案”。

  1. test使用 a作为参数重载test(Class<?> c)定义预期who方法的类。
  2. test()在 class 中隐藏(注意不能覆盖)B
  3. A.test稍作改动执行。

在代码中:

class A {
    public static void who() {
        System.out.println("A");
    }

    public static void test() {
        test(A.class);
    }

    public static void test(Class<?> c) {
        //who(); //<<< How to implement a static:: thing here???
        try {
            c.getMethod("who").invoke(null); // Call static who on given class.
        } catch (Exception e) {
        }
    }

}

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

     public static void test() {
         test(B.class);
     }

     public static void main(String[] args){
        A.test(); // Outputs "A"
        B.test(); // Outputs "B"
     }
}
于 2012-07-16T21:23:52.677 回答
2

B.test即使B没有声明名为test.

Bytecode of main method:

invokestatic #5 = Method B.test(()V)
return

给定类和方法的名称("B""who"),您可以轻松地使用反射来调用该方法。所以问题变成了

你可以B通过结合调用堆栈和字节码来提取A.test吗?

您需要使用存储在堆栈中的返回地址来定位B.test字节码中的调用并提取声明的调用。有很多字节码操作库,但我不知道它们是否允许您将其绑定到 JVM 中的执行堆栈。

于 2012-07-17T22:45:57.477 回答
1

你不能覆盖java中的静态方法。

http://geekexplains.blogspot.co.uk/2008/06/can-you-override-static-methods-in-java.html

于 2012-07-16T21:26:22.240 回答
1

这是Java的一个例子。它使用 Java 8 默认方法和getClass(). 我敢打赌它也适用于类:

interface A {
    default String name() {
       return getClass().getName();
    }
}

class B implements A {}


public class LateBinding {
    public static void main(String[] args) {

        // Create an anonymous class in `LateBinding` (called `$1`)
        System.out.println(new A(){}.name());

        // Instantiate a new `B`
        B b = new B();
        System.out.println(b.name());
    }
}

结果:

$ javac LateBinding.java && java LateBinding
LateBinding$1
B

正如您所看到的,该方法在两种情况下都知道它正在运行,尽管它是在A. 这个例子并不是真正的静态,因为你不能getClass()静态调用,但是 PHP 中的 LSB 并不真正局限于静态上下文。

于 2015-07-28T17:59:49.483 回答
0

使用静态方法声明没有优雅的方法(据我所知,只有 Delphi 支持覆盖静态方法)。但是,如果您不需要静态,您可以编写如下内容:

class A {
    public void who(){
        System.out.println("A");
    };

    public void test(){
        who(); //<<< How to implement a static:: thing here???
    }
}

class B extends A {
    @Override
    public void who(){
        System.out.println("B");
    };
    public void main(String[] args){
        A instance = new A();
        instance.test(); // prints 'A'

        instance = new B();
        instance.test(); // prints 'B'
    }
} 

澄清后编辑: 这样做很hacky的方式:Thread.currentThread().getStackTrace()然后从最顶层的记录获取方法和该方法所属的类。拥有 c 类 - 你可以编写 c.getMethod("who").invoke(null); 调用对应的 who() 方法。

于 2012-07-16T21:28:30.257 回答