2011-01-08 4 views
9

У меня есть статический класс (Foo) и главный класс (Main)Java: как перезапустить статический класс?

См 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 
    } 

} 

См Foo.java:

public class Foo { 

    public static int i = 0; 

} 

Есть ли способ перезапустить или сбросить статический класс?

Примечание: Мне нужно это, потому что я тестирую статический класс с помощью jUnit, и мне нужно очистить параметры перед вторым тестом.


EDIT

ПОЧТИ РЕШЕНИЕ:

Используя StanMax ответ, я могу это:

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


} 

ВЫВОД

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. 

ПРОБЛЕМА: если я бросание ниже:

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

Я получаю сообщение об ошибке:

java.lang.ClassCastException 
+4

Для этого конкретного примера просто сделайте 'Foo.i = 0;' внутри вашего метода 'Main'. – LukeH

+0

У вас есть ClassCastException, потому что класс Foo, загруженный URLClassLoader, отличается от класса Foo, загружаемого ClassLoader, который запускает ваш код (они не ==). Даже если они имеют то же самое определение, вы не можете отбрасывать один на другой. Единственный способ использования этого трюка - если Foo реализует интерфейс FooInterface, который загружается ClassLoader, который разделяется между двумя загрузчиками классов, и в этом случае вы можете использовать FooInterface. Но это не поможет вам получить доступ к статическим полям. – NamshubWriter

+0

NamshubWriter: Хорошо, я сделал это .... но главная проблема в том, что я использую динамический тип .... Я получаю «fooClass не может быть разрешен для типа». Возможно, что-то в Refleion API может помочь ... – Topera

ответ

3

Только если вы можете разгрузить класс, перезагрузите его, так как статический код класса запускается при загрузке класса.

Но вы можете просто напрямую изменить значение:

Foo.i = 0; 

(или создать эквивалентный способ сделать это, особенно, если статический член не является публичной.)

+0

Wow Stax! Но как я могу разгрузить класс? (спасибо!) – Topera

+1

Нелегкий путь; работает только в том случае, если вы фактически контролируете ClassLoader, который использовался для загрузки класса (который вы не делаете, если не создали его). Но если вы это сделаете, вы просто создаете новый ClassLoader, используя класс загрузки. Это НЕ будет влиять на существующие экземпляры «старого» класса, просто создает новое определение класса. – StaxMan

4

Создать статический метод, который устанавливает переменные класса их начальные значения, а затем вызвать его, когда вам это нужно.

+0

Это самый эффективный способ. – Wroclai

+0

У меня большой класс, и я не хочу реорганизовать все, чтобы очищать параметры ... из couse, если я не могу повторно инициализировать класс, мне придется это сделать ... Tks! – Topera

5

Избегайте статичной.

Хорошо известно, что статическое сопротивление не поддается тестированию и поэтому его следует избегать. Например, избегать статичности является одним из ключевых мотивов внедрения инъекций зависимостей. Если вам нужен один экземпляр только во время выполнения, используйте шаблон singleton. И создайте новый экземпляр для каждого тестового прогона.

-4

Вы можете попробовать это.

Main MainObject = new Main; 

MainObject.main(args); 

Он перезапустит класс снова и снова, пока вы не остановите класс.

+1

Нет, это не будет ... – Natix

Смежные вопросы