跳过父构造函数来调用祖父母

问题是这样的:我有一个抽象类在它的构造函数中做了一些工作,还有一组实现抽象类的子类:

class AbstractClass { AbstractClass(){ /* useful implementation */ } } class ConcreteClass1 extends AbstractClass { ConcreteClass1(){ super(); /* useful implementation */ } } 

然后,需要定制具体类,一个解决方案是扩展具体类:

 class CustomizedClass1 extends ConcreteClass1 { CustomizedCLass1(){ super(); /* useful implementation */ } } 

但问题是定制类只需要调用抽象类的构造函数而不是具体类的构造函数。

你是如何实现这一目标的? 改变class级关系的建议是有效的。

编辑:具体示例是ConcreteClass1和CustomizedClass1具有不同的数据集(ConcreteData1和CustomizedData1),并从类的构造函数中的数据库中检索它。 问题是创建CustomizedClass1的实例将检索两个数据实体。

我知道使用简单的inheritance可能不是最好的事情,这就是为什么我指出改变类关系的建议是有效的。

容易(但为什么?):

 class AbstractClass { AbstractClass(){ /* useful implementation */ } } class ConcreteClass1 extends AbstractClass { ConcreteClass1(){ super(); /* useful implementation */ } ConcreteClass1(boolean skip){ super(); } } class CustomizedClass1 extends ConcreteClass1 { CustomizedCLass1(){ super(true); /* useful implementation */ } } 

你不能用Java做到这一点。 我经常有学生想要这样做,但我从未见过他们想要做的事情。

你能给出一个具体的例子,说明你想做什么以及为什么(你的描述太模糊),我相信可以实现一个解决方案:-)

编辑:

对于一个真实世界的例子,为什么你不想这样做(通常)将是一个层次结构,如:

 Animal (constructor makes the eyes) | Mammal (constructor makes the lungs) | Human (constructor sets the language) 

如果Human构造函数可以跳过Mammal构造函数,那么你最终会找到一个没有肺部的人……不是很有用。

根据CustomizedClass1CustomizedClass1任何实例也是ConcreteClass1的实例,因此在CustomizedClass1构造函数可以运行之前,它必须构造为有效的ConcreteClass1实例。 否则,如果你调用ConcreteClass1方法会发生什么? 他们试图对尚未初始化的变量进行操作。

如果您认为需要这样做,那么您的设计需要重新思考。 例如,如果您只想要ConcreteClass1某些function,那么该function可以被分解为ConcreteClass1的超类,而CustomizedClass1可以扩展它以获得它所需的function。

请提供有关这些类之间关系的更多信息。

两条评论:首先,你不应该考虑像这样“跳过”构造函数。 其次,听起来你需要重新思考你的阶级关系。

任何时候你发现自己在想“A延伸B,除了……”是一个非常好的时间来进一步研究事物。 “延伸”意味着“是一个”,这是一种或两种关系:具有可选行为会增加灰色区域,以后会咬你。

正如人们所说,你可以在ConcreteClass1上提供多个构造函数来进行每种情况下所需的初始化,也许可以使它们受到保护,以便它们只能由子类使用。 但是这里有一个问题:如果有人想编写CustomClass2需要一些(但不是全部)ConcreteClass1中的function怎么办? 你添加另一个自定义构造函数?

这听起来像是一个混合的问题 – Java没有很好的处理能力。

虽然它不是您希望的答案或我自豪地键入的答案,但您可以简单地创建模仿ConcreteClass1并使用AbstractClass的构造函数的ConcreteClass1

正如@TofuBeer所说,这不是Java支持的东西。 这就是为什么一些现代语言(即Scala w / Traits)正在获得热情的开发人员。

CustomizedData1是ConcreteData1的子类吗? 如果是这样,那么我建议有一个(可能受保护的)ConcreteClass1构造函数,它接受一个ConcreteData1而不是在初始化期间获取它自己的。 这样,CustomizedClass1可以获取其CustomizedData1并将其传递给对super的调用。 不幸的是,如果您无法在某些内部初始化之前获取数据,这可能会非常棘手或相当不可能。

 class ConcreteClass1 extends AbstractClass { ConcreteClass1(){ this(...fetch data as before...); } ConcreteClass1(ConcreteData1 data){ myData = data; ... } } class CustomizedClass1 extends ConcreteClass1 { CustomizedCLass1(){ super(new CustomizedData1(...)); ... } } 

但是,CustomizedClass1可能需要将数据引用为CustomizedData1而不仅仅是ConcreteData1。 它可能只是对其inheritance的ConcreteData1进行类型转换,但这看起来很令人讨厌。 但是如果它存储自己对数据的引用,那么如果它们不是最终的,则需要保持引用同步。

为什么不实际自定义新创建的ConcreteClass1实例,使其行为类似于AbstractClass实例(前提是ConcreteClass1具有相应的受保护方法)? 即:

 class AbstractClass { public AbstractClass() { /* useful implementation */ } } class ConcreteClass1 extends AbstractClass { public ConcreteClass1() { /* A hidden super() call put here by the compiler. */ /* Useful implementation */ } protected void customize_with(SomeParams customization_params) { /* Customize this ConcreteClass1 instance according to parameters passed. As a result, the instance behavior will 'revert' (in the way you need it) to that of an AbstractClass instance. */ } } class CustomizedClass1 extends ConcreteClass1 { public CustomizedCLass1() { /* A hidden super() call put here by the compiler. */ customize_with(customization_params); /* Rest of useful implementation */ } } 

这里的设计意图和逻辑可能如下:

  1. 你想通过inheritance得到ConcreteClass1的(基本)行为,你从它inheritance(当然这意味着设计它值得inheritance)。

  2. 您希望默认情况下自定义ConcreteClass1提供的行为。 您希望实现的自定义通常可以使用一些参数来描述。 只需将这些参数传递给CustomizedClass1的特殊方法(可以保护),并相应地将其命名为customize()

  3. ConcreteClass1()构造函数中执行的自定义可以是任意的,具体来说,类实例行为可以“恢复”为AbstractClass ,您可能要求它(如果我做对了)。

  4. 调用customize_with()实际上可能会引入一些开销,具体取决于在ConcreteClass1()完成的实际内容,在这种情况下使用重载(并且可能受保护)的构造函数绝对是一个更好的解决方案,除非您希望ConcreteClass1 ‘实例可动态定制(在在哪种情况下, customize_with()和其他的ConcreteClass1应该相应地设计,即通过合同支持这种行为)。

如果语法有什么问题(我没有写很多Java代码),请原谅。

我提出的一种方式:

 class AbstractClass { AbstractClass(){ init(); } protected init(){ /* useful implementation */ } } class ConcreteClass1 extends AbstractClass { ConcreteClass1(){ init(); /* useful implementation */ } } class CustomizedClass1 extends ConcreteClass1 { CustomizedCLass1(){ init(); /* useful implementation */ } } 

通过这种方式,CustomizedClass1从AbstractClass获取所需的行为,而不通过ConcreteClass1初始化。

编辑:哎呀,这不起作用,因为父母的构造函数被隐含地称为评论者指出的一个,我认为简单的方法是拥有不同的构造函数。

是的,你可以调整! 将另一个方法添加到父类(B)并在您的Child类(C)中将其称为super.executeParentA(); 在这个方法中调用super.execute()

 A --> execute() B --> executeParent_A() { super.execute(); } C --> super.executeParent_A(); 

-Mehboob

我可以想到两个人可能想要这样做的事实(实际上并非如此):

情况1,ConcreteClass2从顶级类运行共享初始化,但随后执行自己的初始化序列,它与ConcreteClass1中的不同/冲突 – >有一个init()方法并覆盖它(而不是试图覆盖ConcreteClass1的构造函数) )。

情况2,您有一个(或多个)类成员的多态初始化(这实际上是前一个的特定情况):

 public class ConcreteClass1 extend AbstractClass { protected F1 f; public ConcreteClass1 () { super (); this.f = new F1(); } } public ConcreteClass2 extends ConcreteClass1 { public ConcreteClass2 () { super (); // I'd like to do super.super() instead (no, you don't) this.f = new F2(); // We wasted time with new F1 (); } } 

在这种情况下,要么使用init()方法,要么这样做:

 protected ConcreteClass1 ( F1 f ) { super (); this.f = f; } public ConcreteClass1 () { this ( new F1 () ); } ... public ConcreteClass2 () { super ( new F2 () ); } 

换句话说,明确跳转的原因,隐含跳过层次结构是禁止的,并且在其他答案中解释了很好的理由。