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

В чем смысл использования абстрактных методов?

В чем смысл использования "абстрактных методов"? Абстрактный класс не может быть создан, но как насчет абстрактных методов? Они просто здесь, чтобы сказать "вы должны меня реализовать", и если мы их забудем, компилятор выдает ошибку?

Значит ли это что-то еще? Я также прочитал кое-что о том, что "нам не нужно переписывать один и тот же код", но в абстрактном классе мы просто "объявляем" абстрактный метод, поэтому нам придется переписать код в дочернем классе.

Можете ли вы помочь мне понять это немного больше? Я проверил другие темы об "абстрактном классе/методах", но я не нашел ответа.

4b9b3361

Ответ 1

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

Например, допустим, что у нас есть класс, ответственный за то, что он каким-то образом принимает состояние и манипулирует им. Абстрактный класс будет нести ответственность за получение ввода, преобразование его в long (например) и объединение этого значения с предыдущим значением в некотором роде - что "каким-то образом" является абстрактным методом. Абстрактный класс может выглядеть примерно так:

public abstract class StateAccumulator {
    protected abstract long accumulate(long oldState, long newState);

    public handleInput(SomeInputObject input) {
        long inputLong = input.getLong();
        state = accumulate(state, inputLong);
    }

    private long state = SOME_INITIAL_STATE;
}

Теперь вы можете определить дополнительный накопитель:

public class AdditionAccumulator extends StateAccumulator {
    @Override
    protected long accumulate(long oldState, long newState) {
        return oldState + newState;
    }
}

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

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

Ответ 2

Скажем, у вас есть три принтера, для которых вам нужно будет написать драйвер для Lexmark, Canon и HP.

Все три принтера будут иметь методы print() и getSystemResource().

Однако для каждого принтера будет отличаться только print(). getSystemResource() остается неизменным на всех трех принтерах. У вас также есть другая проблема, вы бы хотели применить полиморфизм.

Итак, поскольку getSystemResource() одинаково для всех трех принтеров, поэтому это можно подтолкнуть к суперклассу, который будет реализован на Java, это можно сделать, сделав этот абстракт в суперклассе и метод в суперклассе, сам класс должен быть абстрактным.

public abstract class Printer{
  public void getSystemResource(){
     // real implementation of getting system resources
  }

  public abstract void print();
}

public class Canon extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Canon
  }
}

public class HP extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to HP
  }
}

public class Lexmark extends Printer{
  public void print(){
    // here you will provide the implementation of print pertaining to Lexmark
  }
}

Обратите внимание, что классы HP, Canon и Lexmark не обеспечивают реализацию getSystemResource().

Наконец, в вашем основном классе вы можете сделать следующее:

public static void main(String args[]){
  Printer printer = new HP();
  printer.getSystemResource();
  printer.print();
}

Ответ 3

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

Итак, возьмем, например, абстрактный класс Shape. Он будет иметь абстрактный метод draw(), который должен его нарисовать. (Shape является абстрактным, потому что мы не знаем, как нарисовать общую форму). Имея абстрактный метод draw в Shape, мы гарантируем, что все производные классы, которые действительно могут быть нарисованы, например, Circle do реализуют draw. Позже, если мы забудем реализовать draw в некотором классе, который получен из Shape, компилятор действительно поможет сделать ошибку.

Ответ 4

Проще говоря, объявляя класс "абстрактным", вы выполняете "контракт" для дочерних классов, которые наследуют его, поэтому он обеспечивает хороший способ поддержания "контракта".

Ответ 5

Если все абстрактные тексты являются абстрактными методами, вы правы, это немного глупо, и интерфейс, вероятно, будет выше.

Но часто абстрактный класс реализует некоторые (возможно, даже все) методы, оставляя лишь несколько абстрактных. Например, AbstractTableModel. Это экономит переписывание большого количества кода.

Еще одно "преимущество" над интерфейсом заключается в том, что абстрактный класс может объявлять поля для использования подклассов. Итак, если вы уверены, что любая разумная реализация будет иметь String с именем uniqueID, вы можете объявить ее, а также соответствующие геттеры/сеттеры, в абстрактном классе, сохраняя некоторую типизацию позже.

Ответ 6

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

Предположим, мы моделировали поведение животных, создав иерархию классов, которая началась с базового класса Animal. Животные способны делать разные вещи, такие как полет, копание и ходьба, но есть некоторые общие операции, такие как прием пищи, сон и шуметь. Некоторые общие операции выполняются всеми животными, но по-другому. Когда операция выполняется другим способом, она является хорошим кандидатом для абстрактного метода (вынуждая подклассы предоставлять пользовательскую реализацию). Давайте посмотрим на очень примитивный базовый класс Animal, который определяет абстрактный метод создания звука (например, лай собаки, мычание коровы или хрюканье pig).

public abstract Animal {

public void sleep{
// sleeping time
}
public void eat(food)
{
//eat something
}
public abstract void makeNoise();
}
public Dog extends Animal {
 public void makeNoise() {
 System.out.println("Bark! Bark!");
 }
}
public Cow extends Animal {
 public void makeNoise() {
 System.out.println("Moo! Moo!");
 }
}

Обратите внимание, что ключевое слово abstract используется для обозначения как абстрактного метода, так и абстрактного класса. Теперь любое животное, которое хочет получить экземпляр (например, собака или корова), должно реализовать метод makeNoise, иначе невозможно создать экземпляр этого класса. Давайте посмотрим на подкласс Dog and Cow, который расширяет класс Animal.

Теперь вы можете задаться вопросом, почему бы не объявить абстрактный класс в качестве интерфейса, и чтобы Dog и Cow реализовали интерфейс. Конечно, вы могли бы - но вам также нужно реализовать методы еды и сна. Используя абстрактные классы, вы можете наследовать реализацию других (неабстрактных) методов. Вы не можете сделать это с интерфейсами - интерфейс не может обеспечить реализацию методов.

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

Ответ 7

Абстрактные методы должны быть переопределены любым подклассом, который не будет абстрактным.

Итак, например, вы определяете абстрактный класс Log, и вы вынуждаете подклассы переопределять этот метод:

public abstract class Log{
  public void logError(String msg){
    this.log(msg,1)
  }
  public void logSuccess(String msg){
    this.log(msg,2)
  }
  public abstract void log(String msg,int level){}
}

public class ConsoleLog{
  public void log(String msg,int level){
    if(level=1){
       System.err.println(msg)
    }else{
       System.out.println(msg)
    }
  }
}