2010-05-02 14 views
11

He leído this question y todavía no estoy seguro de si es posible mantener los punteros a los métodos en una matriz en Java, si alguien sabe si esto es posible o no, sería una verdadera ayuda . Estoy tratando de encontrar una solución elegante para mantener una lista de cadenas y funciones asociadas sin escribir un caos de cientos de 'si'.Matriz de punteros de función en Java

Saludos

Respuesta

24

Java no tiene un puntero de función per se (o "delegate" en el lenguaje C#). Este tipo de cosas tiende a hacerse con subclases anónimas.

public interface Worker { 
    void work(); 
} 

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

class B { 
    void bar() { System.out.println("B"); } 
} 

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

Worker[] workers = new Worker[] { 
    new Worker() { public void work() { a.foo(); } }, 
    new Worker() { public void work() { b.bar(); } } 
}; 

for (Worker worker : workers) { 
    worker.work(); 
} 
+1

aplausos cletus, esto era lo que estaba buscando, el ejemplo ayudó;) – Waltzy

+1

¿Hay algún error? "b.foo();" –

3

Es posible, puede utilizar una gran variedad de Method. Cógelos usando Reflection API (edita: no son funciones ya que no son independientes y tienen que estar asociados con una instancia de clase, pero harían el trabajo, pero no esperes algo como cierres)

+0

Un 'Método' no es realmente un puntero a la función. Por un lado, a menos que llame a un método estático, debe pasarle una instancia. – cletus

+0

Es cierto, pero puede crear un contenedor que lo hará automáticamente. Esto se llamaría algo así como InstanceMethod, e implementar métodos similares a Method, pero delegar las llamadas y pasar a estas llamadas el objeto pasado al constructor. Tal vez las bibliotecas Apache tienen algo como esto? De lo contrario, sería trivial codificar el tuyo. –

+0

crear la tuya es la única forma de aprender. Creo que es otra buena respuesta. – Waltzy

2

Java no tiene punteros (solo referencias), ni tiene funciones (solo métodos), por lo que es doblemente imposible que tenga punteros a las funciones. Lo que puede hacer es definir una interfaz con un único método, sus clases que ofrecen dicho método declaran que implementan dicha interfaz, y hacen que un vector con referencias a dicha interfaz, que se llene con referencias a la específica objetos en los que desea llamar a ese método. La única restricción, por supuesto, es que todos los métodos deben tener la misma firma (número y tipo de argumentos y valores devueltos).

De lo contrario, puede usar la reflexión/introspección (por ejemplo, la clase Method), pero ese no es normalmente el enfoque más simple y natural.

12

Puede lograr el mismo resultado con el patrón de functor. Por ejemplo, tener una clase abstracta:

abstract class Functor 
{ 
    public abstract void execute(); 
} 

Su "funciones" sería en realidad el método execute en las clases derivadas. A continuación, se crea una matriz de funtores y rellenarla con las clases derivadas apropriated:

class DoSomething extends Functor 
{ 
    public void execute() 
    { 
    System.out.println("blah blah blah"); 
    } 
} 

Functor [] myArray = new Functor[10]; 
myArray[5] = new DoSomething(); 

Y entonces se puede invocar:

myArray[5].execute(); 
+4

"dime lo que quiero decir, no lo que pido" Gracias. – Waltzy

1

Tienes razón en que no hay punteros en Java debido a las variables de referencia son las mismas que la sintaxis & en C/C++ que contiene la referencia al objeto, pero no * porque la JVM puede reasignar el almacenamiento dinámico cuando sea necesario, lo que hace que el puntero se pierda de la dirección y provoque un bloqueo. Pero un método es solo una función dentro de un objeto de clase y no más que eso, así que te equivocas al decir que no hay funciones, porque un método es solo una función encapsulada dentro de un objeto. En cuanto a los indicadores de función, el equipo de Java respalda el uso de interfaces y clases anidadas que son buenas y elegantes, pero al ser un programador C++/C# que usa Java de vez en cuando, utilizo mi clase Delegate que hice para Java porque Lo encuentro más conveniente cuando necesito pasar una función y solo tengo que declarar el tipo de devolución del método delegado. Todo depende del programador. Leí las páginas blancas sobre por qué los delegados no son compatibles, pero estoy en desacuerdo y prefiero pensar de manera diferente sobre ese tema.

2

Encontré el enfoque de reflexión el más limpio - agregué un giro a esta solución ya que la mayoría de las clases de producción tienen clases anidadas y no vi ningún ejemplo que demuestre esto (pero tampoco lo busqué por mucho tiempo) .Mi razón para el uso de la reflexión es que mi método "updateUser()" por debajo tenía un montón de código redundante y sólo una línea que cambió (para cada campo en el objeto de usuario) en el medio que actualiza el objeto de usuario:

NameDTO. java

public class NameDTO { 

    String first, last; 

    public String getFirst() { 
     return first; 
    } 

    public void setFirst(String first) { 
     this.first = first; 
    } 

    public String getLast() { 
     return last; 
    } 

    public void setLast(String last) { 
     this.last = last; 
    } 
} 

UserDTO.java

public class UserDTO { 

    private NameDTO name; 
    private Boolean honest; 

    public UserDTO() { 
     name = new NameDTO(); 
     honest = new Boolean(false); 
    } 

    public NameDTO getName() { 
     return name; 
    } 

    public void setName(NameDTO name) { 
     this.name = name; 
    } 

    public Boolean getHonest() { 
     return honest; 
    } 

    public void setHonest(Boolean honest) { 
     this.honest = honest; 
    } 
} 

Example.java

import java.lang.reflect.Method; 

public class Example { 

    public Example() { 
     UserDTO dto = new UserDTO(); 

     try { 
      Method m1 = dto.getClass().getMethod("getName", null); 
      NameDTO nameDTO = (NameDTO) m1.invoke(dto, null); 

      Method m2 = nameDTO.getClass().getMethod("setFirst", String.class); 
      updateUser(m2, nameDTO, "Abe"); 

      m2 = nameDTO.getClass().getMethod("setLast", String.class); 
      updateUser(m2, nameDTO, "Lincoln"); 

      m1 = dto.getClass().getMethod("setHonest", Boolean.class); 
      updateUser(m1, dto, Boolean.TRUE); 
      System.out.println (dto.getName().getFirst() + " " + dto.getName().getLast() + ": honest=" + dto.getHonest().toString()); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    public void updateUser(Method m, Object o, Object v) { 
     // lots of code here 
     try { 
      m.invoke(o, v); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     // lots of code here -- including a retry loop to make sure the 
     // record hadn't been written since my last read 
    } 

    public static void main(String[] args) { 
     Example mp = new Example(); 
    } 
}