2011-01-08 22 views
9

tengo una clase estática (Foo) y una clase principal (Main)Java: ¿cómo "reiniciar" una clase estática?

Ver Main.java:

public class Main { 

    public static void main(String[] args) { 
     System.out.println(Foo.i); // 0 
     Foo.i++; 
     System.out.println(Foo.i); // 1 
     // restart Foo here 
     System.out.println(Foo.i); // 1 again...I need 0 
    } 

} 

Ver Foo.java:

public class Foo { 

    public static int i = 0; 

} 

¿Hay alguna manera de reiniciar o restablecer una clase estática?

Nota: Necesito esto porque estoy probando una clase estática con jUnit y necesito limpiar los parámetros antes de la segunda prueba.


EDITAR

CASI SOLUCIÓN:

Usando respuesta StanMax, lo que pueda para esto:

Main.java

public class Main { 

    public static void main(String[] args) throws Exception { 
     test(); 
     test(); 
    } 

    public static void test() throws Exception { 

     System.out.println("\ntest()"); 

     MyClassLoader myClassLoader = new MyClassLoader(); 
     Class<?> fooClass = myClassLoader.loadClass(Foo.class.getCanonicalName()); 

     Object foo = fooClass.newInstance(); 
     System.out.println("Checking classloader: " + foo.getClass().getClassLoader()); 

     System.out.println("GC called!"); 
     System.gc(); 
    } 

} 

MyClassLoader.java

public class MyClassLoader { 

    private URLClassLoader urlClassLoader; 

    public MyClassLoader() { 
     try { 
      URL url = new File(System.getProperty("user.dir") + "/bin/").toURL(); 
      URL[] urlArray = {url}; 
      urlClassLoader = new URLClassLoader(urlArray, null); 
     } catch (Exception e) { 
     } 
    } 

    public Class<?> loadClass(String name) { 
      try { 
      return (Class<?>) urlClassLoader.loadClass(name); 
     } catch (Exception e) { 
     } 
     return null; 
    } 

    @Override 
    protected void finalize() throws Throwable { 
     System.out.println("MyClassLoader - End.");  
    } 


} 

Foo.java

public class Foo { 

    public static int i = 0; 

    static { 
     System.out.println("Foo - BEGIN ---------------------------------"); 
    } 

    public void finalize() throws Throwable { 
     System.out.println("Foo - End."); 
    } 


} 

SALIDA

test() 
Foo - BEGIN --------------------------------- 
Checking classloader: [email protected] 
GC called! 
MyClassLoader - End. 
Foo - End. 

test() 
Foo - BEGIN --------------------------------- 
Checking classloader: [email protected] 
GC called! 
MyClassLoader - End. 
Foo - End. 

PROBLEMA: si hago el elenco abajo:

Foo foo = (Foo) fooClass.newInstance(); 

me sale error:

java.lang.ClassCastException 
+4

Para este ejemplo en particular, simplemente haga 'Foo.i = 0;' dentro de su método 'Principal'. – LukeH

+0

Tiene ClassCastException porque la clase Foo cargada por URLClassLoader es diferente de la clase Foo cargada por ClassLoader que ejecuta su código (no son ==). Incluso si tienen la misma definición exacta, no puedes lanzar una a la otra. La única forma de que este tipo de truco funcione es si Foo implementa una interfaz FooInterface que es cargada por un ClassLoader que se comparte entre los dos cargadores de clases, en cuyo caso puede enviarlo a FooInterface. Pero eso no ayuda a acceder a los campos estáticos. – NamshubWriter

+0

NamshubWriter: bien, hice esto ... pero el problema principal es porque estoy usando un tipo dinámico ... me aparece "fooClass no puede resolverse en un tipo". Tal vez algo en Refletion API pueda ayudar ... – Topera

Respuesta

3

Solo si puede descargar la clase, vuelva a cargarla, ya que el código estático de la clase se ejecuta cuando se carga la clase.

Pero sólo se puede modificar directamente el valor:

Foo.i = 0; 

(o crear un método equivalente para hacerlo, especialmente si miembro estático no es público.)

+0

Wow Stax! ¿Pero cómo puedo descargar una clase? (¡Gracias!) – Topera

+1

No es una manera fácil; solo funciona si realmente controlas ClassLoader que se usó para cargar la clase (que no lo haces a menos que realmente lo hayas construido). Pero si lo haces, simplemente creas un nuevo ClassLoader, carga la clase utilizándolo. Esto NO afectará las instancias existentes de la clase "anterior", solo crea una nueva definición de Clase. – StaxMan

4

Crear un método estático que establece las variables de clase a sus valores iniciales, y luego llamarlo cuando lo necesite.

+0

Esa es la forma más eficiente. – Wroclai

+0

Tengo una gran clase, y no quiero refactorizar todo para limpiar parámetros ... de couse, si no puedo reiniciar una clase, tendré que hacer esto ... ¡Tks! – Topera

5

Evitar la electricidad estática.

Es sabido que la estática no es comprobable y, por lo tanto, debe evitarse. Por ejemplo, evitar la estática es una de las motivaciones clave detrás de la inyección de dependencia. Si necesita una instancia solo en tiempo de ejecución, use el patrón singleton en su lugar. Y cree una nueva instancia para cada ejecución de prueba.

-4

Puede intentar esto.

Main MainObject = new Main; 

MainObject.main(args); 

Reiniciará la clase una y otra vez hasta que detenga la clase.

+1

No, no ... – Natix

Cuestiones relacionadas