Java:在某些条件下构造子类的超类,可能吗?

Java:在某些条件下构造子类的超类,可能吗?,java,subclass,superclass,Java,Subclass,Superclass,我有这种情况 public class A { public action() { System.out.println("Action done in A"); } } public class B extends A { public action() { System.out.println("Action done in B"); } } 当我创建B的实例时,该操作将只执行B中的操作,因为它覆盖了超类的操作

我有这种情况

public class A {
     public action() {
         System.out.println("Action done in A");
     }
}


public class B extends A {
     public action() {
         System.out.println("Action done in B");
     }
}
当我创建B的实例时,该操作将只执行B中的操作,因为它覆盖了超类的操作

问题是,在我的项目中,超级类A已经使用了太多次,我正在寻找一种方法,在某些情况下,当我创建A的实例时,它会进行检查,如果是真的,则用B替换它自己

public class A {
     public A() {
         if ([condition]) {
            this = new B();
         }
     }

     public action() {
         System.out.println("Action done in A");
     }
}

A a = new A();
a.action();
// expect to see "Action done in B"...

这在某种程度上是可能的吗?

不是直接的,不是。调用
newa()
将始终创建
A
的实例。但是,您可以使
的构造函数受保护,然后使用静态方法:

public static A newInstance() {
  // Either create A or B here.
}

然后将所有当前对构造函数的调用转换为对工厂方法的调用。

如果使用。当您使用构造函数时:不,完全不可能。

我认为这样做:

this = new B();
的构造函数中,
将违反OO设计原则,即使它是可能做到的(事实并非如此)

也就是说,如果我面对这种情况:

问题是,在我的项目中,super class A已经被使用过很多次了

我将用以下两种方法之一解决它:
我假设您的条件是不需要太多类型A的对象,否则可以在任何其他条件下随意替换

选项1:使用工厂设计模式。 选项2:静态计数器+尝试和捕获 在a类中使用静态计数器,通过在构造函数中将静态变量增加1来跟踪a被实例化的次数。如果它达到类型a对象的最大数量限制,则在a的构造函数中抛出一个
InstantiationError

这意味着,无论何时实例化A,都必须使用
try..catch
块拦截
InstantionError
,然后创建类型为
B
的新对象

public class A {

    private static count = 0;
    private static final MAX_COUNT = 100;

    public A() {
        if (count > 100) {
            throw new InstationError();
        }
    }

}
生成对象时:

A obj1, obj2;
try {
    obj1 = new A();
} catch (InstantiationError ie) {
    obj1 = new B();
}
try {
    obj2 = new A();
} catch (InstantiationError ie) {
    obj2 = new B();
}


选项2最接近您在问题中直接提出的问题。但是,我个人会选择使用工厂设计模式,因为它是更优雅的解决方案,它允许你实现你想做的事情。

假设你不愿意将它移动到一个接口或工厂,它有点难看,但你可以在a中保留一个B的delegate副本,并重写你调用委托的方法:

public class A{
  B delegate;

  public A(){
    if([condition]){
      delegate = new B()
      return;
    }
    ...//normal init
  }

  public void foo(){
    if(delegate != null){
      delegate.foo();
      return;
    }
    ...//normal A.foo()
  }

  public boolean bar(Object wuzzle){
    if(delegate != null){
      return delegate.bar(wuzzle);
    }
    ...//normal A.bar()
  }
  ...//other methods in A
}
可以选择是否使用超类的构造函数? 不可能有条件地控制是否使用超类的构造函数,因为在构造自己的对象之前必须调用其中一个超类的构造函数

综上所述,Java中有一个要求,构造函数的第一行必须调用超类的构造函数——事实上,即使没有对超类构造函数的显式调用,也会有对
super()
的隐式调用:

应该强调的是,在执行其他操作之后,不可能调用超类的构造函数:

public class Y extends X {
   public Y() {
     doSomething();  // Not allowed! A compiler error will occur.
     super();        // This *must* be the first line in this constructor.
   }
}
替代方案 也就是说,实现此处所需的方法可以是使用,它可以根据某种条件选择实现的类型:

public A getInstance() {
  if (condition) {
     return new B();
  } else {
     return new C();
  }
}
class Main {
  public static void main(String[] args) {

    // Factory implementation will return ActionPerformerA
    ActionPerformable ap = ActionPerformerFactory.getInstance(true);

    // Invokes the action() method of ActionPerformable obtained from Factory.
    ap.action();    
  }
}
在上述代码中,根据
条件
,该方法可以返回
B
C
的实例(假设两者都是类
a
的子类)

示例

下面是一个具体的示例,使用的是
接口
,而不是

设置以下接口和类:

interface ActionPerformable {
  public void action();
}

class ActionPerformerA implements ActionPerformable {
  public void action() {
    // do something...
  }
}

class ActionPerformerB implements ActionPerformable {
  public void action() {
    // do something else...
  }
}
然后,根据通过方法传入的条件,将有一个类返回上述类之一:

class ActionPeformerFactory {

  // Returns a class which implements the ActionPerformable interface.
  public ActionPeformable getInstance(boolean condition) {

    if (condition) {
      return new ActionPerformerA();
    } else {
      return new ActionPerformerB();
    }
  }
}
然后,一个使用上述工厂方法的类,该类根据条件返回适当的实现:

public A getInstance() {
  if (condition) {
     return new B();
  } else {
     return new C();
  }
}
class Main {
  public static void main(String[] args) {

    // Factory implementation will return ActionPerformerA
    ActionPerformable ap = ActionPerformerFactory.getInstance(true);

    // Invokes the action() method of ActionPerformable obtained from Factory.
    ap.action();    
  }
}

但将这种方法放在
A
中是一种糟糕的设计
A
不应该知道它的子类。工厂方法通常放在不同的类中。@Tadeusz:可能,可能不是。这取决于具体情况。当然,我遇到过这样的情况:父类有一组有限的子类,并且知道它们,认为java枚举模式能够做到这一点。更好的方法是将所有实现都移到另一个类中,并使原始类始终被委托。
class Main {
  public static void main(String[] args) {

    // Factory implementation will return ActionPerformerA
    ActionPerformable ap = ActionPerformerFactory.getInstance(true);

    // Invokes the action() method of ActionPerformable obtained from Factory.
    ap.action();    
  }
}