Зачем нам нужны конструкторы и закрытые члены в абстрактном классе?

Зачем нам нужны конструкторы и закрытые члены в абстрактном классе? Мы не собираемся создавать экземпляр этого класса.

6 ответов

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

Вот пример (не очень полезный, но просто чтобы показать основную идею...)

public abstract class NamedObject
{
    private final String name = name;

    protected NamedObject(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }
}

public class Computer extends NamedObject
{
    private final int processorSpeed;

    public Computer(String name, int processorSpeed)
    {
        super(name); // See, the constructor is useful
        this.processorSpeed = processorSpeed;
    }

    public String toString()
    {
        return getName() + " (" + processorSpeed + ")";
    }
}

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

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

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

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

В зависимости от вашей иерархии ваш абстрактный класс может иметь значение и состояние. Например, если ваше заявление является школой, вы можете иметь представление о человеке (у которого есть имя и SSN), но у вас могут быть разные подтипы для студентов и преподавателей. Поскольку оба типа людей имеют определенную структуру состояний (имя и SSN), оба класса будут расширять класс Person. Но вы никогда не станете просто инстанцировать человека напрямую.

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

// you have this...
public abstract class SomeClass {
    public abstract String returnAString();
}

// ...and this...
public class OtherClass {
    public void operate(SomeClass c) {
        System.out.println(c.returnAString());
    }
}

// ...so you do this:    
OtherClass oc = new OtherClass();
// this is one of the reasons why you need to specify a constructor
oc.operate(new SomeClass() {
    @Override
    public String returnAString() {
        return "I'm an anonymous inner class!";
    }
});

Этот пример, конечно, довольно избыточен, но должен раскрыть суть. Некоторые существующие фреймворки даже полагаются на интенсивное использование этого поведения, по крайней мере, Apache Wicket.

Зачем вам нужен частный класс? Я думаю, что вы путаете абстрактные классы с интерфейсами. В отличие от интерфейсов, абстрактные классы могут содержать функциональность. Например:

public class AbstractBase{
    private int num;

    public AbstractBase(int number){
       this->num = number;
    }

    public int method(){
       return ( this->num * this->templateMethod());
    }

    public abstract int templateMethod();
 }

открытый класс ConcreteDerived extends AbstractBase {

public ConcreteDerived(){
  super(4);
}

public int templateMethod(){
   return number; //number is the result of some calculation
}

}

В этом примере вы никогда не будете явно создавать экземпляр AbstractBase, но, объявляя члены и конструкторы, вы можете настроить функциональность ваших классов (это называется шаблонным методом).

В дополнение к ответу Джона я хотел бы упомянуть, что абстрактные классы по-прежнему хорошо сочетаются с композицией, если дерево подклассов остается мелким. Т.е. он отлично подходит для предоставления общего базового класса для нескольких тесно связанных объектов, но не для создания гигантского дерева подклассов.

Другие вопросы по тегам