猿问

构造函数 newInstance 仅生成本地实例

看来我在测试中错过了一些东西(Robolectrics | Powermockito)。


我与 Singleton 有以下课程:


public class Core{


   private static Core instance = new Core();


   public static Core getInstance() {

        return instance;

    }   


   public static void destroy(){

    instance = null;

   } 

}

在我的测试中,我杀死了instancewithCore.destroy() 并因此Core.getInstance()返回null。


所以我想再次重新生成每个测试instance。我执行以下操作:


Constructor<Core> constructor = Core.class.getDeclaredConstructor();

                constructor.setAccessible(true);

                Core newCore = constructor.newInstance();

所以现在newCore已初始化但Core.getInstance()仍然返回null。


如何正确初始化Core-> instance?


慕盖茨4494581
浏览 149回答 5
5回答

SMILET

在谈论单例时,我经常试图向人们解释一个重要的观点:单例与仅创建 1 个实例的事物之间存在差异。而且,通常,当您认为自己想要一个单例时,实际上您只是想要只创建 1 个实例的东西。这两件事之间的区别一开始可能并不明显,但认识到这一点很重要,特别是当您发现自己需要在测试之间清除单例的内部状态时。如果您有一个单例(真正的单例),根据定义,JVM 中可以存在一个实例。如果它具有可变状态,那么这是有问题的,因为这意味着您必须关心该状态。在测试中,您必须清除运行之间的状态,以消除由于测试执行顺序而产生的任何影响;并且您必须连续运行测试。如果您使用依赖注入(如概念中所示,而不是像 Guice、Dagger、Spring 等任何特定框架),那么使用该实例来自的实例的类并不重要:您作为该类的客户端,得到控制其生命周期。因此,虽然您的生产代码在所有地方使用相同的实例,但您的测试代码可以使用单独的实例 - 因此它们是解耦的- 通常您甚至根本不必担心清理状态,因为您的下一个测试用例可以只需创建该类的一个新实例即可。因此,不要像Core这样使用类的代码:class MyClass {  void foo() {    Core core = Core.getInstance();    // ... do stuff with the Core instance.  }}你可以这样写:class MyClass {  private final Core core;  MyClass(Core core) { this.core = core; }  void foo() {    // ... do stuff with the Core instance.  }}MyClass并且您已经破坏了和之间的静态绑定Core。您可以MyClass在测试中实例化以下单独的实例Core:MyClass myClass = new MyClass(new Core());// Assert something...或者,如果多个实例需要与同一实例交互Core:Core core = new Core();MyClass myClass = new MyClass(core);MyOtherClass myOtherClass = new MyOtherClass(core);// Assert something...

明月笑刀无情

您应该创建构造函数private,以便使用单例类的代码无法使用它创建实例,并且它们应该只能使用该方法获取实例getInstance()。此外,单例对象的生命周期通常与 JVM 相关,因为每个 JVM 都应该有一个单例类的实例。因此,如果您可以销毁并重新创建实例,那么它就不是真正的单例(IMO),所以我假设您只想重新创建实例以进行测试。要在调用该方法后从测试类重新创建单例,destroy()您可以获取Field具有您的类实例的类的 。使用它,Field您可以将其设置为您创建的新实例:public static void main(String[] args) throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Core.getInstance()); //gets instance&nbsp; &nbsp; &nbsp; &nbsp; Core.destroy();&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Core.getInstance()); // null&nbsp; &nbsp; &nbsp; &nbsp; reinitializeInstance(Core.class);&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(Core.getInstance()); //gets instance&nbsp;}public static void reinitializeInstance(Class<Core> clazz) {&nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; Constructor<Core> constructor = clazz.getDeclaredConstructor();&nbsp; &nbsp; &nbsp; &nbsp; constructor.setAccessible(true);&nbsp; &nbsp; &nbsp; &nbsp; Core newCore = constructor.newInstance();&nbsp; &nbsp; &nbsp; &nbsp; Field field = Core.class.getDeclaredField("instance"); //gets the instance field&nbsp; &nbsp; &nbsp; &nbsp; field.setAccessible(true);&nbsp; &nbsp; &nbsp; &nbsp; field.set(newCore, newCore);&nbsp; &nbsp; } catch (Exception e) {&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();&nbsp; &nbsp; }}还有你的 Singleton 类:class Core {&nbsp; &nbsp; private static Core instance = new Core();&nbsp; &nbsp; // To prevent reflection from creating a new instance without destroying the first one&nbsp; &nbsp; private Core() {&nbsp; &nbsp; &nbsp; &nbsp;if(instance != null){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;throw new IllegalStateException("Instance already exists!");&nbsp; &nbsp; &nbsp; &nbsp;}&nbsp; &nbsp; }&nbsp; &nbsp; public static Core getInstance() {&nbsp; &nbsp; &nbsp; &nbsp; return instance;&nbsp; &nbsp; }&nbsp; &nbsp; public static void destroy() {&nbsp; &nbsp; &nbsp; &nbsp; instance = null;&nbsp; &nbsp; }}

慕神8447489

public class Core {&nbsp; &nbsp; private static class SingletonHolder {&nbsp; &nbsp; &nbsp; &nbsp; private static AtomicReference<Core> instance = new AtomicReference(new Core());&nbsp; &nbsp; }&nbsp; &nbsp; public static Core getInstance() {&nbsp; &nbsp; &nbsp; &nbsp; return SingletonHolder.instance.get();&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp; public static void destroy() {&nbsp; &nbsp; &nbsp; &nbsp; SingletonHolder.instance.set(null);&nbsp; &nbsp; }&nbsp;&nbsp; &nbsp; public static void reset() {&nbsp; &nbsp; &nbsp; &nbsp; SingletonHolder.instance.compareAndSet(null, new Core());&nbsp; &nbsp; }&nbsp;}使用额外的“多余”内部类来进行并发初始化,确保静态字段被初始化一次。更改实例(销毁、重置)需要对对象进行某种同步。synchronize可以使用 AtomicReference来代替成本更高的方法。compareAndSet如果已有旧值,则不会为实例设置新值。也是值得拥有的Optional<Core> getInstance() { ... }所以使用是有保障的。Core.getInstance().ifPresent(core -> { ... core ... });

海绵宝宝撒

首先,您要使 Core 构造函数可访问,但默认情况下它已经是公共的。其次,当你调用构造函数时,它只是创建一个新的 Core 实例,它对实例没有任何作用,因为默认创建的构造函数是空的,而且构造函数不是初始化 Singleton 的地方。如果你想刷新单例实例,你应该有一个专用的方法。

幕布斯6054654

换成这个模式怎么样?public class Core{&nbsp; &nbsp;private static Core instance;&nbsp; &nbsp;public static Core getInstance() {&nbsp; &nbsp; &nbsp; &nbsp; if(instance == null) instance = new Core();&nbsp; &nbsp; &nbsp; &nbsp; return instance;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp; &nbsp;public static void destroy(){&nbsp; &nbsp; instance = null;&nbsp; &nbsp;}&nbsp;}如果您只想在测试中销毁,您可以从 destroy() 方法中删除“public”
随时随地看视频慕课网APP

相关分类

Java
我要回答