Java 如何强制在抽象类的所有子类中定义构造函数

Java 如何强制在抽象类的所有子类中定义构造函数,java,constructor,abstract,Java,Constructor,Abstract,我有一个定义抽象方法的抽象类A。这意味着,对于要实例化的类,必须实现所有抽象方法 我希望我的所有子类都实现一个以2个int作为参数的构造函数 声明构造函数违背了我的目的,因为我希望在子类中定义构造函数,而我对实现一无所知。此外,我不能将构造函数声明为抽象的 有办法做到这一点吗 我想要的示例: 假设我正在定义矩阵类的API。在我的问题中,矩阵不能改变它们的维数 对于要创建的矩阵,我需要提供其大小 因此,我希望我的所有实现者都将大小作为参数提供给构造函数。此构造函数是由问题驱动的,而不是由实现问题驱

我有一个定义抽象方法的抽象类A。这意味着,对于要实例化的类,必须实现所有抽象方法

我希望我的所有子类都实现一个以2个int作为参数的构造函数

声明构造函数违背了我的目的,因为我希望在子类中定义构造函数,而我对实现一无所知。此外,我不能将构造函数声明为抽象的

有办法做到这一点吗

我想要的示例:


假设我正在定义矩阵类的API。在我的问题中,矩阵不能改变它们的维数

对于要创建的矩阵,我需要提供其大小

因此,我希望我的所有实现者都将大小作为参数提供给构造函数。此构造函数是由问题驱动的,而不是由实现问题驱动的。只要保留方法的所有语义,实现就可以对这些方法执行任何操作


假设我想在抽象类中提供
invert()
方法的基本实现。此方法将创建一个新矩阵,其中包含
反向维度。更具体地说,由于它是在抽象类中定义的,它将使用一个接受两个int的构造函数创建一个与
this
相同的类的新实例。由于它不知道将使用反射的实例(getDefinedConstructor)我想知道一种方法,我会得到它,并且它对实现来说是有意义的。

您不能在子类中强制构造函数的特定签名,但您可以强制它通过抽象类中的构造函数,取两个整数。子类可以从无参数构造函数调用该构造函数,例如,传入常量。这是你能做到的最接近的了

此外,正如您所说,您对实现一无所知——那么您如何知道他们使用需要两个整数的构造函数是合适的呢?如果其中一个也需要字符串呢?或者对其中一个整数使用常数可能是有意义的

这里的大图是什么?为什么要在子类上强制使用特定的构造函数签名?(正如我所说,您实际上无法做到这一点,但如果您解释为什么需要它,可能会出现一个解决方案。)

一个选项是为工厂提供单独的接口:

interface MyClassFactory
{
    MyClass newInstance(int x, int y);
}

然后,
MyClass
的每个具体子类也需要一个工厂,它知道如何在给定两个整数的情况下构建实例。但这并不十分方便,而且您仍然需要自己构建工厂实例。再说一次,这里的真实情况是什么?

如果需要在接口中定义实现类将使用的内部表示,那么您只是做错了。请去读一读

如果抽象实现依赖于某些实现细节,则它们属于该抽象类。也就是说,抽象类应该定义一个构造函数,该构造函数允许它初始化允许抽象方法工作所需的内部状态


通常,构造函数旨在通过提供对象实例初始状态的一些细节来创建类的实例。这并不意味着正在构造的实例应该像我所看到的大多数软件一样,复制对每个单独参数的引用。因此,即使Java确实提供了一个构造来强制在子类上实现某些构造函数签名,这些子类也可以轻松地放弃参数

你可以试试下面的方法。如果实现类没有具有适当参数的构造函数,则构造函数将引发异常

这太傻了。比较好和坏。这两个类都是相同的,只是OK满足您的需求,因此通过了运行时检查。因此,强制执行该要求会促进事与愿违的繁忙工作

一个更好的解决办法是建立某种工厂

abstract class RequiresConstructor
{
    RequiresConstructor( int x, int y ) throws NoSuchMethodException
    {
    super();
    System.out.println( this.getClass().getName() ) ;
    this.getClass(). getConstructor ( int.class , int.class ) ;
    }

    public static void main( String[] args ) throws NoSuchMethodException
    {
    Good good = new Good ( 0, 0 );
    OK ok = new OK ();
    Bad bad = new Bad ();
    }
}

class Good extends RequiresConstructor
{
    public Good( int x, int y ) throws NoSuchMethodException
    {
    super( x, y ) ;
    }
}

class OK extends RequiresConstructor
{
    public OK( int x, int y ) throws NoSuchMethodException
    {
    super( x, y ) ;
    throw new NoSuchMethodException() ;
    }

    public OK() throws NoSuchMethodException
    {
    super( 0, 0 ) ;
    }
}

class Bad extends RequiresConstructor
{
    public Bad() throws NoSuchMethodException
    {
    super( 0, 0 ) ;
    }
}

让抽象类有一个抽象方法,该方法采用您将要使用的参数。例如:

public abstract void setSize(int rows,int columns);

有点晚了,但是

只需在类中创建一个默认构造函数,它总是被称为超级构造函数。在这个默认构造函数中,您可以检查所有已定义的构造函数,并对其自己的类对象(然后不是抽象的超类,而是具体的子类)进行反射。如果缺少要实现的构造函数,则引发运行时异常

我不是反思的好朋友,因为它有从后门侵入的味道,但有时它会有帮助

看看这个例子:

import java.lang.reflect.Constructor;

public abstract class Gaga {
  public Gaga() {
    boolean found = false;
    try {
      Constructor<?>[] constructors = getClass().getConstructors();
      for (Constructor<?> c : constructors) {
        if (c.getParameterTypes().length==2) {
          Class<?> class0 = c.getParameterTypes()[0];
          Class<?> class1 = c.getParameterTypes()[1];
          if ( (class0.getName().equals("int") || class0.isAssignableFrom(Integer.class))
              &&  (class1.getName().equals("int") || class1.isAssignableFrom(Integer.class)) )
            found = true;
        }
      }
    } catch (SecurityException e)
    {
      found = false;
    }

    if (!found)
      throw new RuntimeException("Each subclass of Gaga has to implement a constructor with two integers as parameter.");

    //...
  }

}
在main函数中,将创建Gaga1的对象,但Gaga2的创建将引发运行时异常

但是你不能确定这个构造函数是否被调用——你甚至不能确保它正在做你想做的事情

此测试仅在处理反射时有用。

高级课程:

public abstract class SupperClass {
  protected Foo foo;

  //primary constructor
  public SupperClass(Foo foo) {
      this.foo = foo;
  }

  private SupperClass(){
    //with this private constructor, the subclass forced to implement primary constructor
  }
}

子类:

public class SubClass extends JLLayer {

  public SubClass(Foo foo) {
      super(foo);
  }
}

如果我在n维空间中定义一个点,我肯定知道这个点不可能存在于m维空间中(m!=n)。因此,在我看来,空间的维度是点的固有属性,而与点的实现无关。据我所知,这是封装和数据抽象。如果要创建的每个实例都必须知道维度,那么要求所有实现提供一个接受此参数的构造函数似乎是很自然的。@dodecaplex,啊,这是一个很好的例子。假设你在谈论一个二维点。当然,我可以用x和y值来表示它。或者,我可以使用弧度/度值和距离值来表示它。朱
public class SubClass extends JLLayer {

  public SubClass(Foo foo) {
      super(foo);
  }
}