【问题标题】:extend an object returned by a static method in java扩展java中静态方法返回的对象
【发布时间】:2013-03-05 17:14:31
【问题描述】:

我有以下问题。

我有一个库类的静态方法(我无法更改),如下所示:

Loader.loadModel()

它返回一个模型类型的对象。

我还创建了一个名为 ExtendedModel 的 Model 子类,它向 Model 添加了一些方法和一些字段。

我做不到:

ExtendedModel m = Loader.loadModel() //compiler error
ExtendedModel m = (ExtendedModel) Loader.loadModel() //ClassCastException at runtime

因为在 Java 中,您不能将超类的对象分配给子类。

但是,我想知道:向 Loader.loadModel() 返回的对象添加方法和字段的最佳方式是什么

【问题讨论】:

  • Loader.loadModel() 返回的实际类型是什么?您需要调查此方法以查看是否可以更改其默认行为。比如它是通过属性获取实现类吗?
  • 在特定情况下可以将超类分配给子类。请参阅下面的答案。
  • 您通常可以使用请求 API(如我的回答中所述)对彼此扩展的所有类和对象执行此操作。
  • Loader.loadModel() 返回的实际类型是Model,我无法更改。

标签: java oop static subclass superclass


【解决方案1】:

你可以试试这个。您的解决方案总是需要粗略的方法。

让“Loader.loadModel()”返回“ExtendedModel”的实例,但返回对象将设置为模型的引用。像这样的:

Model m = Loader.loadModel();

现在您的投射将起作用,如下所示。

ExtendedModel mx = (ExtendedModel) m;

这类似于泛型之前发生的事情。在我上面显示的特定情况下允许向下转换。

【讨论】:

  • 不幸的是,我无法更改 Loader.loadModel() 以使其返回“ExtendedModel”的实例
【解决方案2】:

可以做的是使用 Java Reflect API。这提供了最简单的实现,但可能不如其他解决方案那么快。

您基本上要做的就是将所有数据从 Model 传递给 ExtendedModel,当然让 ExtendedModel 扩展 Model。

我的“模型”类:

public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
    Model model = new Model(1);
    ExtendedModel extended = model.get(ExtendedModel.class);
    extended.setA2("Hello World");
    System.out.println(extended.getA1());
    System.out.println(extended.getA2());
}

private int a1;

public Model() {}
public Model(int a1) {
    this.a1 = a1;
}

public void setA1(int a1) {
    this.a1 = a1;
}

public int getA1() {
    return this.a1;
}

/**
 * This method will transform the current object into an ExtendedModel.
 * @throws SecurityException 
 * @throws NoSuchMethodException 
 * @throws InvocationTargetException 
 * @throws IllegalArgumentException 
 * @throws IllegalAccessException 
 * @throws InstantiationException 
 */
public <T> T get(Class<? extends T> classType) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
    T object = classType.getConstructor().newInstance();

    // pass all the data via setters
    for (Field field : this.getClass().getDeclaredFields()) {
        String methodName = "set"+StringUtil.ucfirst(field.getName()); // uppercase first!
        classType.getMethod(methodName, field.getType()).invoke(object, field.get(this));
    }

    // return object
    return object;
}

我的“ExtendedModel”课程:

public class ExtendedModel extends Model {

    private String a2;

    public ExtendedModel() {}

    public String getA2() {
        return this.a2;
    }

    public void setA2(String a2) {
        this.a2 = a2;
    }

}

当然,您也可以使用 getter 而不是直接访问属性。这将帮助您轻松地将解决方案与其他类/对象一起使用。唯一重要的是:

  1. 声明一个默认构造函数(没有参数或一组已知参数)。
  2. 将所有数据从“Model”复制到“ExtendedModel”或您想要扩展的任何类。

【讨论】:

    【解决方案3】:

    您不能,但您可以使用adapter pattern,它只是另一个类,将具有原始对象类型的字段,然后您可以对该对象执行操作。

    【讨论】:

      【解决方案4】:

      虽然您添加了一个新类,但您没有该类的新实例。为了能够使用模型的附加方法和字段,您需要有一个ExtendedModel 的实例; Loader.loadModel() 返回“常规”Model 的实例,从而导致问题。

      要扩展对象的功能,您需要编写一个包装类。包装器通常采用“基”类的对象,将基本功能委托给它,并添加自己的一些方法/变量:

      public class ExtendedModel : Model {
          private final Model wrapped;
          public ExtendedModel(Model model) { wrapped = model; }
          private int addedField = 123;
          // Methods of the Model that you did not change simply forward the calls:
          public void doSomething() { wrapped.doSomething(); }
          public int calculateSomething() { return wrapped.calculateSomething(); }
          // Extended methods do whatever you need them to do:
          public int getAddedField() {return addedField;}
          public void increment() {addedField++;}
      }
      

      现在您可以像这样创建ExtendedModel 的实例:

      ExtendedModel m = new ExtendedModel(Loader.loadModel());
      

      【讨论】:

        【解决方案5】:

        你不能

        这就是面向对象编程的工作方式。如果你想添加任何额外的功能,编写一个包含静态方法的帮助类,它接受 Model 并返回一些所需的值,例如int, double, ...

        【讨论】:

          猜你喜欢
          • 2011-05-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-07-12
          • 2015-03-28
          • 1970-01-01
          相关资源
          最近更新 更多