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

时间:2009-12-10 04:03:45

标签: java oop

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

class AbstractClass {
     AbstractClass(){ /* useful implementation */ }
}

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

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

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

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

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

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

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

10 个答案:

答案 0 :(得分:21)

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

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

编辑:

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

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

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

答案 1 :(得分:10)

容易(但为什么?):

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 */ }
}

答案 2 :(得分:8)

根据定义,CustomizedClass1的任何实例也是ConcreteClass1的实例,因此必须必须才能构建为ConcreteClass1实例。{{ 1}}构造函数可以运行。否则,如果您在其上调用CustomizedClass1方法会发生什么?他们试图对尚未初始化的变量进行操作。

如果您认为自己需要这样做,那么您的设计需要重新思考。例如,如果您只想要ConcreteClass1中的某些功能,那么该功能可以被分解为ConcreteClass1的超类,并且ConcreteClass1可以扩展它以获得它的功能需要。

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

答案 3 :(得分:7)

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

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

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

答案 4 :(得分:1)

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

虽然这不是您希望的答案或者我自豪地键入的答案,但您可以创建模仿ConcreteClass2的{​​{1}}并使用ConcreteClass1的构造函数。

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

答案 5 :(得分:1)

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。它可能只是对其继承的ConcreteData1进行类型转换,但这看起来很令人讨厌。但如果它存储自己对数据的引用,那么如果它们不是最终的,则需要保持引用同步。

答案 6 :(得分:0)

为什么不实际自定义新创建的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. 你希望通过继承得到ConcreteClass1的(基本)行为,你继承它(这当然是设计它值得继承)。

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

  3. ConcreteClass1()构造函数中执行的自定义可以是任意的,具体而言,可以将类实例行为“还原”为AbstractClass的自定义行为,这可能是您要求的(如果我做对了)。

  4. 调用customize_with()实际上可能会引入一些开销,具体取决于ConcreteClass1()中的实际内容,在这种情况下使用重载(并且可能受保护)的构造函数绝对是一个更好的解决方案,除非你愿意像ConcreteClass1'实例一样可以动态定制(在这种情况下customize_with()可能应该相应地设计ConcreteClass1的其余部分,即通过合同支持这种行为。“

  5. 如果语法有任何问题(我没有编写太多Java代码),请原谅。

答案 7 :(得分:0)

我提出的一种方式:

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初始化。

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

答案 8 :(得分:0)

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

A --> execute() 

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

C --> super.executeParent_A();

-Mehboob

答案 9 :(得分:0)

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

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

案例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 () );
}

换句话说,要明确跳转的原因,禁止隐式跳过层次结构,并在其他答案中解释这个原因。