Java - Могут ли потомки абстрактного класса ("extends"-ers) создавать себя с помощью абстрактного метода своих родителей?"Т.е. m = new this();"?
Перво-наперво, пожалуйста, имейте в виду, что я пытаюсь выразить свой вопрос как можно лучше, используя мои текущие знания и словарный запас, поэтому, пожалуйста, извините это...
У меня есть абстрактный класс, в котором я хочу создать метод, в котором он создает себя... Конечно, это невозможно в абстрактном классе, однако, что я действительно хочу, это для конкретных детей (тех классов, которые "расширяются") унаследовать это создание, чтобы они могли создать себя...
В основном то, что я хочу сделать, это:
MyAbstract a = new this ();
Однако это не разрешено... Есть ли способ, которым я могу делать то, что я хочу?
Вот некоторый некомпилируемый код мечты (т.е. код, который я хотел бы сработать). По сути, я хочу, чтобы ConcreteChild вызывал метод, в котором он создает сам объект. Метод наследуется от его родителя.
public class Abstract {
public void instantiateMyConcreteChild()
{
Abstract a = new this();
}
}
public class ConcreteChild extends Abstract{
public static void main(String[] args) {
ConcreteChild c = new ConcreteChild();
c.instantiateMyConcreteChild();
}
}
* Дополнительная информация **
Спасибо за ответы, но я думаю, что пропустил что-то жизненно важное....
По сути, я хотел передать self объекта ( "this") в некоторые методы некоторых других классов. Однако создание экземпляра другого объекта внутри объекта немного отсталый, я могу просто передать "this", верно...
5 ответов
Вы можете сделать это, используя отражение, что-то вроде:
Abstract a = getClass().newInstance();
Это потому, что getClass() всегда возвращает конкретный класс, поэтому this.getClass() вернет реальный подкласс, а не текущий класс.
Однако имейте в виду, что если подкласс определяет пользовательский конструктор, имеющий больше или меньше параметров, чем ваш абстрактный класс, он может потерпеть неудачу. Если вы не укажете в документации, что у подклассов должен быть конструктор с такими заданными параметрами... но он все равно хрупок.
Вы можете проверить это, используя getClass(). GetConstructors() и посмотреть, какие есть конструкторы, и если есть тот, который вы ожидаете, или даже найти жизнеспособный, в противном случае вы можете поймать исключение, генерируемое newInstance(..), и оберните его в более описательное исключение для пользователей, чтобы они лучше понимали, что они пропустили... но это все равно было бы своего рода хаком, потому что в такой ситуации нет явной языковой поддержки.
Другим подходом может быть реализация Cloneable в вашем абстрактном классе, а затем использование метода clone, но это может быть излишним или даже неправильным, если вам нужен новый, чистый экземпляр.
Вы не можете сделать это, используя метод экземпляра. Поскольку, как следует из названия, методы экземпляра требуют, чтобы экземпляр уже был создан.
Вы пытаетесь определить конструктор, который могут использовать подклассы Abstract? Если это так, вы можете просто сделать это так же, как вы определяете любой другой конструктор.
public class Abstract {
Abstract() {
//set fields, etc. whatever you need to do
}
}
public class ConcreteChild extends Abstract{
ConcreteChild() {
//call superclass's constructor
super();
}
}
Что вам на самом деле нужно сделать, это отделить неизменяющуюся внутреннюю функциональность от самого абстрактного класса. Так что я мог бы, к примеру, иметь внутренний класс, который действительно инкапсулирует неизменяемые функциональные возможности, например, так:
public class Abstract {
public void instantiateMyConcreteChild()
{
Abstract a = new NonChangingOperations();
}
class NonChangingOperations
{
public void operationA() {}
}
}
На самом деле вам не нужно хранить класс NonChangingOperations как внутренний класс, вы можете сделать его как внешний служебный класс со своей собственной иерархией классов.
Не могли бы вы просто иметь это?
public abstract class AbstractClassWithConstructor {
public AbstractClassWithConstructor() {
init();
}
protected abstract void init();
}
FYI
В targe t-c вам нужно установить это, вызвав метод init. Метод init() будет выглядеть так:
protected AbstractClassWithConstructor init() {
return this;
}