簡體   English   中英

如何從另一個類的靜態方法獲取抽象類的子類的實例?

[英]How can I get an instance of a subclass of abstract class from a static method of another class?

我有以下類結構:

  • DataStore類:

    • 父類: PStorepublic abstract class PStore ...
    • 擴展它的2個子類: CStore1CStore2
    • 每個子類都是N-glton(對不起,不確定Java術語是什么) - 它只能有N個實例,編號為1..NMax。
    • 每個子類具有以下訪問該實例的方法: CStore1.getInstance(Id)CStore2.getInstance(Id)
  • 工人班:

    • 父類: public abstract class PWork...
    • 擴展它的2個子類: CWork1CWork2
  • 現在的情況:

    • CWork1實現了一個內部類,其中以下代碼訪問了Store:

       protected class fListener implements ActionListener { public void actionPerformed(ActionEvent ae) { CStore1.getInstance(Id).someMethod(); # NOTE: someMethod() is implemented in CStore2 as well } } 
    • 我需要在CWork2實現相同的fListener

    • 作為一個優秀的小軟件開發人員,我不是簡單地將fListenerCWork1復制/粘貼到CWork2類,然后在其代碼CStore1 CStore2更改為CStore2 ,而是決定將其遷移到父類。


  • 我試圖做的:

    • PStore創建一個名為getStoreInstance(int Id)的抽象方法: public abstract PStore getStoreInstance(int Id);

    • CStore1將該方法實現為public PStore getStoreInstance(int Id) { return CStore1.getInstance(Id); } public PStore getStoreInstance(int Id) { return CStore1.getInstance(Id); }

      到現在為止還挺好。 它編譯了所有3個Store類。

    • 將fListener代碼從PWork復制到CWork1

    • 顯然,編譯器抱怨它對CStore1類及其方法getStoreInstance()一無所知

    • 現在,我決定簡單地調用新創建的getStoreInstance()

      舊代碼: CStore1.getInstance(Id).someMethod();

      新代碼: PStore.getStoreInstance(Id).someMethod();

  • 編譯器投訴 :“無法從PStore類型中對靜態方法getStoreInstance(Id)進行靜態引用”。

  • Eclipse提出的唯一“修復”是使getStoreInstance()方法保持靜態,但是THAT也不起作用:

    • 當我向抽象類的方法聲明添加一個static修飾符時: public static abstract PStore getStoreInstance(int Id); - 編譯器抱怨“PStore類型中的抽象方法getStoreInstance只能設置一個公開或受保護的可見性修飾符”

    • 當我試圖使方法非抽象時: public static PStore getStoreInstance(int Id); 它抱怨說這個方法需要一個身體(非常合理)

    • 當我試圖添加一個身體時,它要求我返回PStore對象......但是!!!! 我的抽象類PStore沒有構造函數,所以我無法返回PStore對象!


我正確地解決了這個問題嗎?

如果沒有,我該怎么辦呢?

如果我是,那么我如何解決原始投訴 “無法對非靜態方法進行靜態引用”,因為抽象類不允許我將該方法設為靜態?

它看起來對我來說,你有兩個同構的層次結構(如果我使用的是正確的術語)並且相應的類之間存在關系:

      PStore                   PWork
      /     \                 /     \
     /       \               /       \
   CStore1  CStore2        CWork1   CWork2
      ^         ^              ^      ^  
      |         |              |      | 
      |---------+--------------|      |
                |                     |
                |---------------------|

但我不認為有一種內置的方式來表達Java中的這種關系。 不知何故,你將不得不做一些使這些關系明確的事情。 也就是說, CWork1中需要有一些引用CStore1東西, CWork2中引用CStore2 ,或者某種與它們相關聯的列表或地圖。

可能有一種解決這種結構的設計模式,但我現在想不到它。 所以,在我的腦海中,這里有幾個可能的解決方案(兩者都不使用反射):

  1. 將您在PWork定義的抽象getStoreInstance方法替換為PStore CWork1 ,使用調用CStore1.getInstance的方法覆蓋它,類似地在CWork2覆蓋它。 然后,常見的fListener actionPerformed代碼將調用getStoreInstance(Id).someMethod() ,沒有類名,這可以在當前的PWork實例上運行。 您仍然會有一些“重復”代碼(因為您必須在兩個CWork類中實現getStoreInstance ),但它會保持最小化。

  2. 設置地圖。 這編譯(Java 8),但我沒有測試它:

     class PWork { private static Map<Class<? extends PWork>,IntFunction<PStore>> storeMap; static { storeMap = new HashMap<>(); storeMap.put(CWork1.class, CStore1::getInstance); storeMap.put(CWork2.class, CStore2::getInstance); } protected PStore getStoreInstance(int Id) { return storeMap.get(getClass()).apply(Id); } protected class fListener implements ActionListener { public void actionPerformed(ActionEvent ae) { int Id = ???; // I'm assuming Id is computed from ae somehow?? getStoreInstance(Id).someMethod(); } } } 

現在, getStoreInstance在地圖中查找,使用當前PWork對象的類( CWork1CWork2 )作為鍵,以確定要調用的getInstance靜態方法。

是的,您可以在PStore上使用靜態方法並且沒有重復代碼。

使您的工作人員具有通用性,保留類令牌引用並調用

public class Worker<T extends PStore> {
    private final Class<T> c;
    public Worker(Class<T> c) {
        this.c = c;
    }

    public void actionPerformed(ActionEvent ae) {
        PStore.getInstance(c, Id).someMethod();
    }
    // other methods
}

現在對於PStore中的靜態方法,它不必是通用方法:worker不必知道返回的實際類型,它只是正確的類型。

public class PStore {
    private static Map<Class<?>, List<PStore>> map = new HashMap<>();

    protected PStore() {
        List<PStore> list = map.get(getClass());
        if (list == null) {
            list = new ArrayList<>();
            map.put(getClass(), list);
        }
        list.add(this);
    }

    public static PStore getInstance(Class<? extends PStore> c, int i) {
        return map.get(c).get(i);
    }
    public abstract void someMethod();
}

這里的好處是N個實例的上限留給了PStore子類。 還要注意列表如何包含PStore實例,它們實際上是子類實例,但PStore和worker都不關心(只要它實際上是返回的所需子類,它將是)。

免責聲明:我在手機上輸入了這個,所以可能無法編譯 - 如果有問題請告訴我,我會嘗試修復它。

編譯器是正確的,因為在靜態上下文中引用實例方法不起作用。 在靜態世界中,您正在處理類級別並處理整個類的屬性。 如果您嘗試調用實例方法,編譯器如何知道您要執行實例方法的實例?

制作抽象方法不起作用,因為抽象方法必須在子類中實現。 但是,靜態方法不能被覆蓋 - 只能隱藏。 因此,如果在抽象方法上允許static ,並且您嘗試執行AbstractClass.staticMethod() ,那么運行時將使用哪些實現?

你的代碼有點難以理解,但這就是我的想法。 基於名稱, getStoreInstance(int Id)應該確實是一個靜態方法,因為實例獲取另一個實例沒有多大意義; 這似乎更像是班級應該做的事情。 您可能想重新考慮如何構建代碼...從代碼名稱來看,您似乎應該使用類級別的方法來跟蹤類的實例,因此可能會執行類似的操作並實現getInstance()getStoreInstance()作為靜態方法將是一個開始?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM