miércoles, octubre 06, 2010

Uso del paquete java.lang.reflect

Utilizando las funcionalidades del paquete java.lang.reflect se pueden manipular, en tiempo de ejecución, los métodos y atributos de una clase. Por ejemplo, si se tienen todos los métodos de ordenación en una clase de nombre Algoritmos, se puede crear un método genérico que invoque a cualquiera de ellos sin utilizar un bloque condicional mediante la funcionalidad de "reflexión" de los métodos de la clase Algoritmos.

En el siguiente código, se asume que los métodos de ordenación publicados se encuentran en una clase de nombre "Algoritmos" y que se ha importado el paquete java.lang.reflect. El método ejecutarMetodo recibe como parámetro el nombre del método de la clase Algoritmos que implementa el algoritmo de ordenación requerido, así como el vector a ordenar, y devuelve el tiempo en segundos que tardó la ejecución del mismo.


public static double ejecutarMetodo(String nombreMetodo, int[] v) {
        try {
            Method m = Algoritmos.class.getMethod(nombreMetodo, v.getClass());
            double t1 = System.currentTimeMillis();
            m.invoke(null, v);
            double t2 = System.currentTimeMillis();
            return (t2-t1)/1000.0 ;
        }
        catch(Exception x) {
            System.out.println(x.getMessage());
            System.exit(0);
            return 0;
        }
    }


Para probar el funcionamiento de esta característica se puede crear una clase diferente, en este caso la clase TestReflect que se puede ejecutar desde la línea de comandos para recibir una lista de métodos de ordenación que se van a probar con tamaños de vector desde 1 en potencias de 2. A continuación se muestra el código de implementación de la clase TestReflect. Para efectos de prueba se incluyeron dos nombres de método por default, en caso de que la clase no se ejecute desde la línea de comandos:

public class TestReflection {
    public static void main(String[] args) {
        String[] tmp =  {"ordenacionInsercion", "ordenacionRapida"};
        if(args.length==0) args = tmp;
        int n=1;
        while(n<Integer.MAX_VALUE) {
            System.out.printf("%,12d ", n);
            for(String algoritmo: args) {
                int[] v = Algoritmos.crearVector(n);
                System.out.printf("%,12f ",Algoritmos.ejecutarMetodo(algoritmo, v));
            }
            System.out.println();
            n*=2;
        }
    }
}

En este caso en particular, los resultados para los dos algoritmos probados, con tamaños de vector por encima de 1,024 son los siguientes:

1.024     0,001000     0,000000 
       2.048     0,004000     0,000000 
       4.096     0,013000     0,001000 
       8.192     0,053000     0,000000 
      16.384     0,219000     0,002000 
      32.768     0,863000     0,005000 
      65.536     3,377000     0,010000 
     131.072    13,468000     0,019000 
     262.144    54,277000     0,041000 
     524.288   220,892000     0,085000 

Del análisis de estos datos se puede detectar fácilmente que el incremento en el tiempo requerido para ordenar un vector es aproximadamente cuatro veces mayor cuando el tamaño del vector aumenta al doble, mientras que para el de ordenación rápida, el incremento es ligeramente superior al doble. Ambas observaciones se corresponden con lo esperado según el análisis de su complejida.

No hay comentarios.:

Publicar un comentario

Multiprocesamiento recursivo en JAVA 7

Una de las estrategias de diseño de algoritmos más comunes es la de "divide y vencerás", en la cual, un problema de tamaño relativ...