2012-07-16 10 views
7
<?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" 
?> 

Quiero conseguir un equivalente en Java ... así que algo comoEquivalente a finales de unión estática (PHP) en otros idiomas populares

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

Quiero la llamada who() dentro A::test para resolver como en PHP 5.3 llamando al B::who.

EDIT: Sé que no hay una "forma estándar" de hacer esto en la mayoría de los idiomas populares. Estoy buscando hacks y tal. Además, ¿esto es posible en C/C++ o en cualquier otro lenguaje OOP popular?

Esto no es para ningún diseño real en nada. Solo estoy siendo curioso.

+0

Eso es un rollo. Entonces, debido a que es una función estática, técnicamente no se puede modificar y la capacidad de llamarlo como B.test() es solo una pequeña conveniencia dada a los usuarios. Por lo tanto, puede tomarse la libertad de descartar la información de tipo en el sitio de llamada. ¿Estoy en lo correcto? – jetru

+0

Ok, voy a dejar esto encendido por un tiempo, alguien brillante podría tener una idea genial. – jetru

+0

Estaba incorrecto sobre el compilador. Vea mi respuesta, aunque todavía no resuelve el problema completo. –

Respuesta

2

No es posible en Java. (Al menos no sin hacks de reflexión feos.)

Lo aliento a replantear su diseño y confiar en los objetos adecuados.

pregunta relacionada:

Editar:B.test() será (o, al menos de acuerdo a las especificaciones) compilarse en una llamada a A.test(), así que no hay manera de descubre cómo se realizó la llamada desde A.test(). En otras palabras, no hay forma de que el comportamiento de A.test dependa de si se llamó a través de A.test() o B.test().

Dado que estás preguntando por curiosidad, aquí está AFAIK la "solución" más cercana.

  1. sobrecarga test con un test(Class<?> c) que toma como argumento la clase que define el who método previsto.
  2. Ocultar (tenga en cuenta que no puede anular) test() en la clase B.
  3. Y cambie la implementación de A.test levemente.

En código:

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

Sí, estoy buscando hacks de reflexión feos. Este no es un diseño real para nada. Aprendí esto sobre PHP y me pregunto cómo serán las construcciones comparables en otros idiomas. – jetru

0

No hay manera elegante de hacerlo con declaración de método estático (Sólo Delphi de lo que yo soy consciente de soportes para anular los métodos estáticos). Sin embargo, si estática no es necesario que usted puede escribir algo como esto:

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

EDITAR después de la clarificación: manera Bastante hacky de hacer esto: Thread.currentThread().getStackTrace() luego de método get más superficial de grabación y de clase este método pertenece. Tener clase c: puedes escribir c.getMethod ("quién"). invocar (nulo); llamar al método who() correspondiente.

+0

... ¿simplemente está sugiriendo que suelte la palabra clave 'static'? – aioobe

+0

Eso es correcto :) –

+0

Por favor, vea editar. – jetru

2

Parece que el compilador genera una llamada a B.test en el código de bytes aunque B no declara un método denominado test.

Bytecode of main method: 

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

Teniendo en cuenta los nombres de una clase y el método ("B" y "who") que pueda usar la reflexión para llamar al método. Entonces la pregunta es

¿Se puede extraer B mediante la combinación de la pila de llamadas y el código de bytes dentro A.test?

Deberá utilizar la dirección de devolución almacenada en la pila para ubicar la llamada al B.test en el código de bytes y extraer la llamada declarada. Hay muchas bibliotecas de manipulación de códigos de bytes, pero no sé si alguna de ellas te permite vincularlas a la pila de ejecución en la JVM.

1

He aquí un ejemplo de Java. Utiliza los métodos por defecto de Java 8 y getClass(). Apuesto a que trabaja con clases demasiado:

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

Resultados:

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

Como se puede ver el método sabe en ambos casos en los que se está ejecutando, aunque se define en A. Este ejemplo no es realmente estático, porque no puede llamar al getClass() estáticamente, pero LSB en PHP no está realmente limitado a contextos estáticos.

Cuestiones relacionadas