Java:新手的继承问题
假设我有一个基类B和一个派生类D。我希望在基类中有一个方法foo(),该方法返回实例的任何类型的新对象。例如,如果我调用B.foo()它将返回一个类型为B的对象,而如果我调用D.foo()它将返回一个类型为D的对象;同时,实现只驻留在基类B中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
这可能吗?只要每个类都有一个默认构造函数:
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测试。。。