繁体   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