Java:新手的继承问题

Java:新手的继承问题,java,inheritance,types,derived-class,base-class,Java,Inheritance,Types,Derived Class,Base Class,假设我有一个基类B和一个派生类D。我希望在基类中有一个方法foo(),该方法返回实例的任何类型的新对象。例如,如果我调用B.foo()它将返回一个类型为B的对象,而如果我调用D.foo()它将返回一个类型为D的对象;同时,实现只驻留在基类B中 这可能吗?只要每个类都有一个默认构造函数: public B instance() throws Exception { return getClass().newInstance(); } abstract class

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


这可能吗?

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

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

我认为这可能是通过反射实现的,即在你的超类中你有:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}
其中ClassName是基类的名称

你必须把它扔到你想用的任何地方。。。我不确定这真的是一个很好的解决方案

Edit:newInstance()类型的方法通常是静态的,当然,对于静态方法,您不知道子类的类型是什么


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

好吧,我可能会关闭,但我会假设,由于“this”总是指当前对象,您可以执行以下操作

public B foo() {
    return this.getClass().newInstance();
}
还是类似的?如果您创建一个D的实例,然后调用D.foo(),您应该会得到一个D的实例作为B返回。您可以将其作为普通对象返回,但我认为在这个实例中您应该尽可能具体。

@Rik

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


然后,我有很多子类,比如BigThing、LittleThing、something,我不想为它们中的每一个重写getnexthing()方法。这看起来很浪费,因为他们都这么做。。。事情


我的方法不对吗?

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

public class B <X extends B>{

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

}
公共B类{
public X foo()抛出实例化异常,IllegalAccessException{
返回(X)this.getClass().newInstance();
}
}        
公共类C扩展了B{
}
让我给你提个建议。CS课程的教学方式往往是教授们热衷于继承,但还没有弄清楚组成。我想你可能要找的是作文。所以,与其对这个东西本身调用getNextThing,不如考虑让它实现


这意味着您只需要编写一个可以封装获取下一个对象的逻辑,因为它似乎不适合您的继承模型。另一个优点是,您可以从中获得一些很好的语法工具(增强循环理解)。

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

在您的问题中,您使用的是静态(类)方法,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();  
        }
    }
}

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

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

e、 g

然后,对于没有默认构造函数的子类,只有在确实需要时才可以重写getNewInstance()

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}
不要。将“foo”方法抽象化

abstract class B {
    public abstract B foo();
}
或通过基类构造函数接收抽象工厂:

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

添加协变返回类型和泛型以供尝试。

是否有特定的原因使您希望将实现保留在基类中?当您陈述一个“新手”问题时,您可能会得到更有价值的答案,说明您的潜在问题。我相信你的问题一定有比你在问题中使用的B和D更好的解决方案。不,使用你的问题的反思答案,你应该能够按照你的意愿实现这一点,这对我来说似乎很好。我认为你必须进行反思。“这似乎是浪费,因为他们都做相同的……事情。”它很少浪费。你有子类是有原因的。通常,每个子类都有一个不同的构造函数或初始化之类的东西。它们很少完全相同。只有当您有默认构造函数时,反射才会起作用。使用反射方法会起作用,但只有在这种情况下,这使得创建子类时很容易出错。不是。还有,为什么你认为这是设计缺陷的产物?这是可行的,但不要声明抛出泛型“Exception”类的方法。我采取相反的方法——只在客户机a)关心并且b)从不同的环境中恢复时声明多个异常。否则它只是视觉混乱,例如演示和JUnit测试。。。