如何从另一个类的静态方法获取抽象类的子类的实例?

时间:2014-05-14 22:04:12

标签: java static abstract-class subclass instance-variables

我有以下类结构:

  • 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
              }
          }
      
    • 我需要在fListener

    • 中实施相同的CWork2课程
    • 成为优秀的小型软件开发人员,而不是简单地将fListenerCWork1复制/粘贴到CWork2课程,然后将CStore1更改为CStore2在其代码中,我决定将其转移到父类中。


  • 我尝试做的事情:

    • 在名为PStore的{​​{1}}中创建一个抽象方法:getStoreInstance(int Id)

    • public abstract PStore getStoreInstance(int Id); 中将该方法实施为CStore1

      到目前为止,这么好。它编译了所有3个商店类。

    • 将fListener代码从public PStore getStoreInstance(int Id) { return CStore1.getInstance(Id); }复制到PWork

    • 显然,编译器抱怨它对CStore1类及其方法CWork1

    • 一无所知
    • 现在,我决定只调用新创建的getStoreInstance()

      旧代码:getStoreInstance()

      新代码:CStore1.getInstance(Id).someMethod();

  • 编译器投诉:“无法从PStore类型中对非静态方法getStoreInstance(Id)进行静态引用”。

  • Eclipse提出的唯一“修复”是将getStoreInstance()方法设为静态,但这样做也不起作用:

    • 当我在抽象类的方法声明中添加PStore.getStoreInstance(Id).someMethod();修饰符时:static - 编译器抱怨“PStore类型中的抽象方法getStoreInstance只能设置可见性修饰符,一个公共的或受保护的“

    • 当我试图让这个方法变得非抽象时:public static abstract PStore getStoreInstance(int Id);它抱怨该方法需要一个体(非常合理)

    • 当我试图添加一个身体时,它要求我返回PStore对象......但是!!!!我的抽象类PStore没有构造函数,所以我无法返回PStore对象!!!


我是否正确接近了问题?

如果没有,我应该如何处理?

如果我是,那么我可以解决原始投诉关于“无法对非静态方法进行静态引用”,因为抽象类没有放弃我让那个方法静止了吗?

3 个答案:

答案 0 :(得分:1)

它看起来对我来说,你有两个同构的层次结构(如果我使用正确的术语)并且相应的类之间存在关系:

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

但我不认为有一种内置的方式来表达Java中的这种关系。 不知何故,你将不得不做一些使这些关系明确的事情。即需要CWork1中引用CStore1的内容,CWork2内引用CStore2的内容,或者某种与之关联的列表或地图。

可能有一种设计模式可以解决这个问题,但我现在想不到它。所以,在我的脑海中,这里有几个可能的解决方案(两者都不使用反射):

  1. 将您在getStoreInstance中定义的抽象PWork方法替换为PStore。在CWork1中,使用调用CStore1.getInstance的方法覆盖它,类似地在CWork2中覆盖它。然后,常见的fListener actionPerformed代码将调用getStoreInstance(Id).someMethod(),没有类名,这将适用于当前的PWork实例。您仍然会有一些“重复”代码(因为您必须在getStoreInstance个类中实现CWork),但它会保持最低限度。

  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();
           }
        }
    
     }
    
  3. 现在getStoreInstance在地图中查找,使用当前PWork对象的类(CWork1CWork2)作为关键字,找出getInstance静态方法来调用。

答案 1 :(得分:1)

是的,你可以在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都不关心(只要它实际上是返回的所需子类,它将会是这样)。

免责声明:我在手机上输入了这个内容,因此可能无法编译 - 请告诉我是否有问题,我会尝试修复它。

答案 2 :(得分:0)

编译器是正确的,因为在静态上下文中引用实例方法不起作用。在静态世界中,您正在处理类级别并处理整个类的属性。如果您尝试调用实例方法,编译器如何知道您要执行实例方法的实例?

使抽象方法不起作用,因为必须在子类中实现抽象方法。但是,静态方法不能被覆盖 - 只能隐藏。因此,如果在抽象方法上允许static,并且您尝试执行AbstractClass.staticMethod(),那么运行时将使用哪种实现?

您的代码有点难以理解,但这就是我的想法。基于名称,getStoreInstance(int Id)应该是一个静态方法,因为实例获取另一个实例没有多大意义;这似乎更像是班级应该做的事情。您可能想重新考虑如何构建代码...从代码名称来看,您似乎应该使用类级别的方法来跟踪类的实例,因此可能会执行类似的操作并实现{{1}和getInstance()作为静态方法会是一个开始吗?