相当于其他流行语言中的后期静态绑定(PHP)

时间:2012-07-16 21:21:20

标签: java php c++ python

<?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来解析,就像在PHP 5.3中一样。

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

这不适用于任何实际设计。我只是好奇。

5 个答案:

答案 0 :(得分:2)

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

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

相关问题:

编辑: B.test()将(或至少可以根据规范)编译成对A.test()的调用,因此无法发现如何在A.test()内进行通话。换句话说,没有办法让A.test的行为取决于它是通过A.test()还是B.test()调用的。

既然你好奇了,这里是AFAIK最接近的“解决方案”。

  1. 使用test重载test(Class<?> c),该参数将定义预期who方法的类作为参数。
  2. 在课程test()
  3. 隐藏(请注意,您无法覆盖)B
  4. 稍微更改A.test的实施。
  5. 在代码中:

    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"
         }
    }
    

答案 1 :(得分:2)

似乎编译器在字节码中生成对B.test的调用,即使B未声明名为test的方法。

Bytecode of main method:

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

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

  

您可以通过在B内组合调用堆栈和字节码来提取A.test吗?

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

答案 2 :(得分:1)

答案 3 :(得分: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并不仅限于静态上下文。

答案 4 :(得分: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()方法。