2011-01-08 12 views
9

Mam klasy statycznej (foo) i główne klasy (główny)Java: jak "zrestartować" klasę statyczną?

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

} 

See Foo.java:

public class Foo { 

    public static int i = 0; 

} 

Czy istnieje jakiś sposób, aby zrestartować lub zresetować klasę statyczną?

Uwaga: Potrzebuję tego, ponieważ testuję klasę statyczną z jUnit i muszę wyczyścić parametry przed drugim testem.


EDIT

PRAWIE ROZWIĄZANIE:

Korzystanie StanMax odpowiedź, mogę do tego:

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."); 
    } 


} 

WYJŚCIE

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. 

PROBLEM: jeśli robię obsady poniżej:

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

otrzymuję błąd:

java.lang.ClassCastException 
+4

Dla tego konkretnego przykładu po prostu wykonaj 'Foo.i = 0;' wewnątrz twojej metody 'Main'. – LukeH

+0

Masz wyjątek ClassCastException, ponieważ klasa Foo załadowana przez obiekt URLClassLoader różni się od klasy Foo ładowanej przez klasę ClassLoader, na której działa kod (nie są ==). Nawet jeśli mają dokładnie taką samą definicję, nie można rzutować jednego na drugi. Jedyny sposób działania tego rodzaju sztuczki polega na tym, że Foo implementuje interfejs FooInterface, który jest ładowany przez klasę ClassLoader, która jest współdzielona między dwa programy ładujące klasy, w którym to przypadku można rzutować na FooInterface. Ale to nie ułatwia dostępu do pól statycznych. – NamshubWriter

+0

NamshubWriter: ok, Zrobiłem to ... ale głównym problemem jest to, że używam typu dynamicznego ... Dostaję "fooClass nie może być rozwiązany na typ". Może coś w Refletion API może pomóc .... – Topera

Odpowiedz

3

Tylko jeśli można usunąć klasę, pobierz ją ponownie, ponieważ kod klasy klasy zostanie wykonany po załadowaniu klasy.

Ale można tylko bezpośrednio zmodyfikować wartość:

Foo.i = 0; 

(lub utworzyć metodę równoważną by to zrobić, szczególnie jeśli członek statyczny nie jest publiczna.)

+0

Wow Stax! Ale jak mogę wyładować klasę? (dzięki!) – Topera

+1

Nie ma łatwego sposobu; działa tylko wtedy, gdy faktycznie kontrolujesz ClassLoader, który został użyty do załadowania klasy (która nie jest wymagana, chyba że ją skonstruowałeś). Ale jeśli to zrobisz, po prostu stwórz nową klasę ClassLoader, załaduj klasę za jej pomocą. To NIE wpłynie na istniejące instancje "starej" klasy, po prostu tworzy nową definicję klasy. – StaxMan

4

Tworzenie statycznej metody, która ustawia zmienne klasy do wartości początkowej, a następnie połączyć je, gdy jest to potrzebne.

+0

To najbardziej efektywny sposób. – Wroclai

+0

Mam dużą klasę i nie chcę niczego wymieniać, żeby wyczyściła parametry ... na wypadek, gdybym nie mogła ponownie zainicjować klasy, będę musiał to zrobić ... Tks! – Topera

5

Unikaj statyczne.

Powszechnie wiadomo, że nie można przeprowadzić testu statycznego i dlatego należy go unikać. Na przykład unikanie statycznych jest jedną z głównych motywacji zastrzyku zależności. Jeśli potrzebujesz tylko jednej instancji w środowisku wykonawczym, zamiast tego użyj wzorca singleton. I stwórz nową instancję dla każdego uruchomienia testowego.

-4

Możesz spróbować tego.

Main MainObject = new Main; 

MainObject.main(args); 

Spowoduje to ponowne uruchomienie klasy ponownie, dopóki nie zatrzymasz zajęć.

+1

Nie, nie będzie ... – Natix

Powiązane problemy