亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

構造函數 newInstance 僅生成本地實例

構造函數 newInstance 僅生成本地實例

慕蓋茨4494581 2023-07-13 13:57:39
看來我在測試中錯過了一些東西(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?
查看完整描述

5 回答

?
SMILET

TA貢獻1796條經驗 獲得超4個贊

在談論單例時,我經常試圖向人們解釋一個重要的觀點:

單例與僅創建 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...


查看完整回答
反對 回復 2023-07-13
?
明月笑刀無情

TA貢獻1828條經驗 獲得超4個贊

您應該創建構造函數private,以便使用單例類的代碼無法使用它創建實例,并且它們應該只能使用該方法獲取實例getInstance()。


此外,單例對象的生命周期通常與 JVM 相關,因為每個 JVM 都應該有一個單例類的實例。因此,如果您可以銷毀并重新創建實例,那么它就不是真正的單例(IMO),所以我假設您只想重新創建實例以進行測試。


要在調用該方法后從測試類重新創建單例,destroy()您可以獲取Field具有您的類實例的類的 。使用它,Field您可以將其設置為您創建的新實例:


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

        System.out.println(Core.getInstance()); //gets instance

        Core.destroy();

        System.out.println(Core.getInstance()); // null

        reinitializeInstance(Core.class);

        System.out.println(Core.getInstance()); //gets instance

 }


public static void reinitializeInstance(Class<Core> clazz) {

    try {

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

        constructor.setAccessible(true);

        Core newCore = constructor.newInstance();


        Field field = Core.class.getDeclaredField("instance"); //gets the instance field

        field.setAccessible(true);

        field.set(newCore, newCore);


    } catch (Exception e) {

        e.printStackTrace();

    }

}

還有你的 Singleton 類:


class Core {


    private static Core instance = new Core();


    // To prevent reflection from creating a new instance without destroying the first one

    private Core() {

       if(instance != null){

           throw new IllegalStateException("Instance already exists!");

       }

    }


    public static Core getInstance() {

        return instance;

    }


    public static void destroy() {

        instance = null;

    }


}


查看完整回答
反對 回復 2023-07-13
?
慕神8447489

TA貢獻1780條經驗 獲得超1個贊

public class Core {


    private static class SingletonHolder {

        private static AtomicReference<Core> instance = new AtomicReference(new Core());

    }


    public static Core getInstance() {

        return SingletonHolder.instance.get();

    }   


    public static void destroy() {

        SingletonHolder.instance.set(null);

    } 


    public static void reset() {

        SingletonHolder.instance.compareAndSet(null, new Core());

    } 

}

使用額外的“多余”內部類來進行并發初始化,確保靜態字段被初始化一次。


更改實例(銷毀、重置)需要對對象進行某種同步。synchronize可以使用 AtomicReference來代替成本更高的方法。


compareAndSet如果已有舊值,則不會為實例設置新值。


也是值得擁有的


Optional<Core> getInstance() { ... }

所以使用是有保障的。


Core.getInstance().ifPresent(core -> { ... core ... });


查看完整回答
反對 回復 2023-07-13
?
海綿寶寶撒

TA貢獻1809條經驗 獲得超8個贊

首先,您要使 Core 構造函數可訪問,但默認情況下它已經是公共的。

其次,當你調用構造函數時,它只是創建一個新的 Core 實例,它對實例沒有任何作用,因為默認創建的構造函數是空的,而且構造函數不是初始化 Singleton 的地方。

如果你想刷新單例實例,你應該有一個專用的方法。


查看完整回答
反對 回復 2023-07-13
?
幕布斯6054654

TA貢獻1876條經驗 獲得超7個贊

換成這個模式怎么樣?


public class Core{


   private static Core instance;


   public static Core getInstance() {

        if(instance == null) instance = new Core();

        return instance;

    }   


   public static void destroy(){

    instance = null;

   } 

}

如果您只想在測試中銷毀,您可以從 destroy() 方法中刪除“public”


查看完整回答
反對 回復 2023-07-13
  • 5 回答
  • 0 關注
  • 217 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號