Подтвердить что ты не робот

Как я могу заставить конструктор быть определен во всех подклассах моего абстрактного класса

У меня есть абстрактный класс A, который определяет абстрактные методы. Это означает, что для того, чтобы класс был неустойчивым, весь абстрактный метод должен быть реализован.

Я хотел бы, чтобы все мои подклассы реализовали конструктор с 2 ints в качестве параметров.

Объявление конструктора поражает мою цель, поскольку я хочу, чтобы конструктор был определен в подклассах, и я ничего не знаю о реализации. Более того, я не могу объявить конструктор абстрактным,

Есть ли способ сделать это?

Пример того, что я хочу:

Позволяет сказать, что я определяю API класса Matrix. В моей проблеме Matrix не может изменить свои размеры.

Чтобы создать матрицу, мне нужно указать ее размер.

Следовательно, я хочу, чтобы все мои разработчики предоставили конструктору размер в качестве параметра. Этот конструктор мотивирован проблемой, а не проблемой реализации. Реализация может делать все, что захочет, при условии, что сохраняется вся семантика методов.

Скажем, я хочу предоставить базовую реализацию метода invert() в моем абстрактном классе. Этот метод создаст новую матрицу с инвертированными размерами this. Более конкретно, поскольку он определен в абстрактном классе, он создаст новый экземпляр того же класса, что и this, используя конструктор, который принимает два ints. Поскольку он не знает экземпляр, он будет использовать рефлексию (getDefinedConstructor), и я хочу, чтобы способ гарантировать, что я получу его и что это будет иметь смысл для реализации.

4b9b3361

Ответ 1

Вы не можете принудительно создать определенную подпись конструктора в своем подклассе, но вы можете заставить его пройти через конструктор в абстрактном классе с двумя целыми числами. Подклассы могли бы вызвать этот конструктор из конструктора без параметров, например, проходящего в константах. Что ближе всего вы можете прийти.

Кроме того, как вы говорите, вы ничего не знаете о реализации - так как вы знаете, что для них целесообразно иметь конструктор, который требует двух целых чисел? Что делать, если одному из них нужна строка? Или, возможно, имеет смысл использовать константу для одного из этих целых чисел.

Какая большая картина здесь - почему вы хотите заставить определенную подпись конструктора в своих подклассах? (Как я уже сказал, вы не можете этого сделать, но если вы объясните, почему вы этого хотите, может возникнуть решение.)

Один из вариантов - иметь отдельный интерфейс для factory:

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

Тогда каждому из ваших конкретных подклассов MyClass также понадобится factory, который знал, как построить экземпляр с двумя целыми числами. Это не очень удобно, хотя - и вам все равно нужно будет создавать экземпляры самих фабрик. Опять же, какова реальная ситуация здесь?

Ответ 2

Если вам нужно определить в своем интерфейсе внутреннее представление, которое будут использовать реализующие классы, тогда вы просто делаете это неправильно. Пожалуйста, прочитайте encapsulation и абстракция данных.

Если ваша абстрактная реализация зависит от определенных деталей реализации, то они относятся к этому абстрактному классу. Значение абстрактного класса должен определять конструктор, который позволяет ему инициализировать внутреннее состояние, необходимое для работы абстрактных методов.

Как правило, конструкторы предназначены для создания экземпляра класса, предоставляя некоторые сведения об исходном состоянии экземпляра этого объекта. Это не означает, что создаваемый экземпляр должен копировать ссылку на каждый отдельный аргумент, как это часто бывает в большинстве программ, которые я вижу. Поэтому, даже если Java действительно предложила конструкцию для принудительной реализации определенных подписи Constructor на подклассах, эти подклассы могли легко отбросить аргументы.

Ответ 3

Вы можете попробовать что-то вроде ниже. Конструктор выкинет исключение, если класс реализации не имеет конструктора с соответствующими аргументами.

Это глупо. Сравните OK и Bad. Оба класса одинаковы, за исключением того, что OK соответствует вашему требованию и, таким образом, передает проверки времени выполнения. Таким образом, соблюдение этого требования способствует непроизводительной занятости.

Лучшим решением будет какой-то Factory.

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 ) ;
    }
}

Ответ 4

Немного поздно, но...

Просто создайте конструктор по умолчанию в своем классе, который всегда называется супер-конструктором. В этом конструкторе по умолчанию вы можете проверить все определенные конструкторы с отражением на собственном объекте класса (который тогда не является абстрактным суперклассом, а конкретным подклассом). Если конструктор, который вы хотите реализовать, отсутствует, выведите исключение во время выполнения.

Я не отличный друг, потому что у него есть вкус взлома через черный ход, но иногда это помогает...

Взгляните на этот пример:

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.");

    //...
  }

}

И тестовый класс:

public class Test {
  private class Gaga1 extends Gaga {
    public Gaga1() { this(0, 0); }
    public Gaga1(int x, Integer y) { }
  }

  private class Gaga2 extends Gaga {

  }

  public static void main(String[] args)
  {
    new Gaga1();
    new Gaga1(1, 5);
    new Gaga2();
    System.exit(0);
  }
}

В основной функции будут созданы объекты Gaga1, но создание Gaga2 вызовет исключение во время выполнения.

Но вы не можете быть уверены, что этот конструктор вызван - вы даже не можете убедиться, что он делает то, что вам нужно.

Этот тест полезен, если вы работаете с отражением.

Ответ 5

У абстрактного класса есть абстрактный метод, который принимает то, что у вас будет для параметров. Например:

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