Java:新手式继承问题

时间:2020-03-06 15:04:28  来源:igfitidea点击:

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

这可能吗?

解决方案

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

public B instance() throws Exception {
        return getClass().newInstance();
    }

我认为可以使用反射来做到这一点,即在超类中有:

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

其中ClassName是基类的名称。

不过,无论我们要在哪里使用它,都必须将其强制转换。我不确定这是否是一个很好的解决方案!

编辑:newInstance()类型的方法通常是静态的,当然,我们对静态方法的子类的类型一无所知。

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

好吧,我可能会离开,但我会假设由于" this"始终指向当前对象,因此我们可以执行以下操作

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

或者类似的规定?如果我们创建D的实例,然后调用d.foo(),则应获得D的实例作为B返回。我们可以将其作为普通对象返回,但在这种情况下应尽可能具体。

@里克

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

然后,我有许多子类,例如BigThing,LittleThing,SomethingThing,并且我不想继续为每个子类重写getNextThing()方法。看起来很浪费,因为他们都做同样的事情。

我的方法不正确吗?

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

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实现Iterable,而不是对Thing本身调用getNextThing。

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

除了我认为如果要完成此设计可能存在设计缺陷之外,还可以尝试以下方法。

在问题中,我们使用的是静态(类)方法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()(确保捕获InstantiationException和IllegalAccessException)。

如果任何构造函数都需要参数,则可以使用反射或者(在我的视图中最好)定义一个类似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);
}

别。使" 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();
}

添加协变量返回类型和泛型。