Equivalent to late static binding (PHP) in other popular languages

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

I want to get the equivalent in Java ... so something like

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

I want the who() call inside A::test to resolve as in PHP 5.3 by calling B::who .

EDIT: I know that there is no “standard way” to do this in most popular languages. I am looking for hacks and the like. Also, is this possible in C / C ++ or any other popular OOP language?

This is for no real design. I'm just curious.

+7
source share
5 answers

Impossible in Java. (At least not without ugly reflective hacks.)

I urge you to rethink your design and rely on relevant objects.

Related Question:

Edit: B.test() will (or at least according to the specification) be compiled into a call to A.test() , so there is no way to find out how the call from A.test() . In other words, A.test behavior should not be allowed to depend on whether it was invoked through A.test() or B.test() .

As you ask out of curiosity, AFAIK is the closest "solution" here.

  • Overloading test with test(Class<?> c) , which takes as an argument a class that defines the intended who method.
  • Hide (note that you cannot override) test() in class B
  • And slightly change the implementation of A.test .

In code:

 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" } } 
+2
source

It seems that the compiler generates a B.test call in bytecode, although B does not declare a method called test .

 Bytecode of main method: invokestatic #5 = Method B.test(()V) return 

Given the class and method names ( "B" and "who" ), you can easily use reflection to invoke the method. So the question becomes

Can you extract B by combining the call stack and bytecode inside A.test ?

You will need to use the return address stored on the stack to find the B.test call in the bytecode and retrieve the declared call. There are many bytecode manipulation libraries, but I don’t know if any of them can link this to the executive stack in the JVM.

+2
source
+1
source

Here is an example from Java. It uses the default methods of Java 8 and getClass() . I bet it works with classes too:

 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()); } } 

Results:

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

As you can see, this method knows in both cases when it works, although it is defined in A This example is not static because you cannot call getClass() statically, but LSB in PHP is not really limited to static contexts.

+1
source

There is no elegant way to do this by declaring a static method (only Delphi from what I know about override support for static methods). However, if you don't need static, you can write something like this:

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

EDIT after clarification: Pretty hacky way to do this: Thread.currentThread (). GetStackTrace () , then from the getLead method itself and the class to which this method belongs. The presence of class c - you can write c.getMethod ("who"). Invoke (null); to call the who () method.

0
source

All Articles