3

假设我有一个基类 B 和一个派生类 D。我希望在我的基类中有一个方法 foo(),它返回一个实例类型的新对象。因此,例如,如果我调用 B.foo() 它返回一个 B 类型的对象,而如果我调用 D.foo() 它返回一个 D 类型的对象;同时,实现仅驻留在基类 B 中。

这可能吗?

4

8 回答 8

3

只要每个类都有一个默认构造函数:

    public B instance() throws Exception {
        return getClass().newInstance();
    }
于 2008-10-03T13:30:24.387 回答
3

不。使“foo”方法抽象。

abstract class B {
    public abstract B foo();
}

或者通过基类构造函数接收一个抽象工厂:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

添加协变返回类型和泛型来品尝。

于 2008-10-03T14:33:13.870 回答
1

我认为这可能使用反射来完成,即在你的超类中你有:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

其中 ClassName 是您的基类的名称。

不过,您必须将它投射到任何您想使用它的地方……我不确定这是否真的是一个很好的解决方案!

编辑: newInstance() 类型方法通常是静态的,当然您不会知道使用静态方法的子类的类型是什么。

我认为没有任何方法可以让静态方法(动态)创建子类的实例。

于 2008-10-03T13:31:33.790 回答
1

好吧,我可能会离开,但我会假设因为“this”总是指当前对象,你可以做类似的事情

public B foo() {
    return this.getClass().newInstance();
}

或类似的规定?如果你创建一个 D 的实例然后调用 d.foo() 你应该得到一个作为 B 返回的 D 的实例。你可以将它作为一个普通的 Object 返回,但我认为在这个实例中你应该尽可能具体。

于 2008-10-03T13:34:05.377 回答
1

除了我认为如果你想实现这一点可能存在设计缺陷之外,你可以尝试以下方法。

在您的问题中,您正在使用静态(类)方法,B.foo(),D.foo(),这不能使用继承来完成,因为静态方法不具有动态特性,它们不参与查找系统。所以你没有足够的类型信息。

如果您使用的是成员函数 foo(),则可以具有以下构造:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}
于 2008-10-03T13:45:32.157 回答
1

正如其他答案所说,如果每个子类中都有一个无参数构造函数(确保捕获 InstantiationException 和 IllegalAccessException),则可以使用 getClass().newInstance() 。

如果任何构造函数需要参数,您可以使用反射或(在我看来更可取)定义一个类似 getNewInstance() 的方法,您可以仅在需要时在子类中覆盖该方法。

例如

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

然后 getNewInstance() 只有在你真的需要时才能被覆盖,对于没有默认构造函数的子类。

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}
于 2008-10-03T13:48:20.060 回答
0

@里克

好吧,真正的问题是我有一个抽象基类 Thing。Thing 有一个名为 getNextThing() 的方法,它返回一个新的 Thing 实例。

然后,我有许多子类,如 BigThing、LittleThing、SomethingThing,我不想为每个子类重写 getNextThing() 方法。这似乎很浪费,因为他们都做同样的事情......

我的方法不正确吗?

于 2008-10-03T13:37:49.333 回答
0

我不确定你为什么要尝试做你真正想做的事情。提供更多上下文可能会让我们为您提供更多帮助。

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

让我给你这个建议。教授 CS 课程的方式往往是教授迷恋继承,但还没有弄清楚作文。我认为您可能正在寻找的是构图。因此,与其在 Thing 本身上调用 getNextThing,不如考虑让 Thing 实现Iterable

这意味着您只需要编写一个可以封装获取下一事物的逻辑的迭代器,因为它似乎不适合您的继承模型。这样做的另一个优点是您可以从中获得一些不错的句法设备(增强了循环理解)。

于 2008-10-03T13:43:22.300 回答