Как я могу заставить конструктор быть определенным во всех подклассах моего абстрактного класса
у меня есть абстрактный класс, который определяет абстрактные методы. Это означает, что для того, чтобы класс был инстанцируемым, все абстрактные методы должны быть реализованы.
Я хотел бы, чтобы все мои подклассы реализовали конструктор с 2 ints в качестве параметров.
объявление конструктора поражает мою цель, так как я хочу, чтобы конструктор определялся в подклассах, и я ничего не знаю о реализации. Кроме того, я не могу объявить конструктор как аннотация;
есть ли способ сделать это ?
пример того, что я хочу:
допустим, что я определяю API матричного класса. В моей проблеме Матрица не может изменить свои размеры.
чтобы создать матрицу, мне нужно указать ее размер.
следовательно, я хочу, чтобы все мои разработчики предоставили конструктору размер в качестве параметра. Этот конструктор мотивирован проблемой, а не реализацией беспокойство. Реализация может делать с ними все, что захочет, при условии, что все семантические методы сохранены.
допустим, я хочу обеспечить базовую реализацию invert() метод в моем абстрактном классе. Этот метод создаст новую матрицу с this обратных измерений. Более конкретно, как это определено в абстрактном классе, он создаст новый экземпляр того же класса, что и this, используя конструктор, который принимает два ints. Как он не знает экземпляр он будет использовать отражение (getDefinedConstructor) и я хочу способ гарантировать, что я получу его и что это будет иметь смысл для реализации.
5 ответов:
вы не можете заставить конкретную подпись конструктора в вашем подклассе - но вы можете заставьте его пройти через конструктор в вашем абстрактном классе, взяв два целых числа. Подклассы может вызовите этот конструктор из конструктора без параметров, передавая константы, например. Это самое близкое, что вы можете сделать.
более того, как вы говорите, вы ничего не знаете о реализации - так как вы знаете, что это подходит для них есть конструктор, который требует два целых числа? Что, если одному из них тоже нужна Струна? Или, возможно, имеет смысл использовать константу для одного из этих целых чисел.
какова здесь общая картина -почему вы хотите заставить конкретную подпись конструктора на ваших подклассах? (Как я уже сказал, Вы не можете на самом деле do это, но если вы объясните, почему вы хотите его, решение может представить себя.)
один из вариантов-отдельный интерфейс для фабрики:
interface MyClassFactory { MyClass newInstance(int x, int y); }затем каждый из ваших конкретных подклассов
MyClassтакже нужна фабрика, которая знает, как построить экземпляр с двумя целыми числами. Это не очень удобно, хотя - и вам все равно нужно будет создавать экземпляры самих заводов. Опять же, какова реальная ситуация здесь?
вы можете попробовать что-то вроде ниже. Конструктор выдаст исключение, если реализующий класс не имеет конструктора с соответствующими аргументами.
Это глупо. Сравните хорошо и плохо. Оба класса одинаковы, за исключением того, что 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 ) ; } }
Если вам нужно определить в своем интерфейсе внутреннее представление, которое будут использовать классы реализации, то вы просто делаете это неправильно. Пожалуйста, прочитайте о инкапсуляция и абстракции данных.
Если ваша абстрактная реализация опирается на определенные детали реализации, то они принадлежат к этому абстрактному классу. Это означает, что абстрактный класс должен определить конструктор, который позволяет ему инициализировать внутреннее состояние, необходимое для разрешения абстрагированные методы для работы.
Как правило, конструкторы предназначены для создания экземпляра класса, предоставляя некоторые подробности первоначального состояния экземпляра объекта. Это не означает, что создаваемый экземпляр должен копировать ссылку на каждый отдельный аргумент, как это часто бывает в большинстве программ, которые я вижу. Поэтому, даже если Java действительно предлагала конструкцию для принудительной реализации определенных сигнатур конструктора на подклассах, те подклассы могли легко откажитесь от аргументов.
немного поздно, но...
просто создайте конструктор по умолчанию в своем классе, который всегда вызывается как супер конструктор. В этом конструкторе по умолчанию вы можете проверить все определенные конструкторы с отражением на своем собственном объекте класса (который тогда не является абстрактным суперклассом, а конкретным подклассом). Если конструктор, который вы хотите реализовать, отсутствует, создайте исключение среды выполнения.
Я не большой друг отражения, потому что у него есть вкус взлом через заднюю дверь, но иногда это помогает...
взгляните на этот пример:
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 вызовет исключение времени выполнения.
но вы не можете быть уверены, что этот конструктор называется - вы даже не можете гарантировать, что он делает то, что вы хотите.
этот тест полезен только если вы работаете с отображение.
у абстрактного класса есть абстрактный метод, который принимает то, что у вас было бы для параметров. Например:
public abstract void setSize(int rows,int columns);
Comments