Абстрактные классы и методы в Java, Наследование - PullRequest
10 голосов
/ 06 января 2009

У меня есть класс B, который наследуется от класса A. Суперкласс A является абстрактным, содержащим один абстрактный метод. Я не хочу реализовывать абстрактный метод в классе B, поэтому мне нужно также объявить класс B как абстрактный. Объявляя класс B абстрактным, у меня работают две вещи (программы компилируются и работают правильно):

1.) Я не объявляю никаких абстрактных методов в классе B, даже думал, что класс абстрактный. Это работает, я полагаю, потому что класс наследует абстрактный метод класса A, и этого достаточно для того, чтобы класс был объявлен как абстрактный: нам не нужны никакие другие абстрактные методы, прямо объявленные в классе.

2.) Я объявляю тот же абстрактный метод в классе B, который был объявлен в классе A. Это своего рода переопределение (?), Не в том же смысле, что переопределение в java (с использованием того же заголовка, но предоставление другой реализации), здесь я просто снова использую тот же заголовок метода.

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

Здесь я приведу несколько примеров классов, так что то, что я имею в виду, будет для вас более понятным:

Случай 1.):

public abstract class A {
    public abstract String giveSum();
}

public abstract class B extends A {

}

Случай 2.):

public abstract class A {
    public abstract String giveSum();
}

public abstract class B extends A {
    public abstract String giveSum();
}

Привет

Ответы [ 5 ]

35 голосов
/ 06 января 2009

В Java аннотация класса abstract указывает, что класс не может быть напрямую создан. Класс может быть объявлен abstract просто потому, что он никогда не должен создаваться (возможно, он содержит только статические методы), или потому что вместо него должны создаваться экземпляры его подклассов.

Это , а не требование, чтобы abstract классы содержали abstract методов (обратное равно true: класс, содержащий один или несколько abstract методов, должен иметь значение abstract.)

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

Основной аргумент против переопределения метода abstract состоит в том, что дублирующий код плох - он делает рефакторинг более громоздким и тому подобным (применимы все классические аргументы «не дублируйте код»).

8 голосов
/ 06 января 2009

Они функционально равны, но первый предпочтительнее, потому что он короче и не странный.

2 голосов
/ 06 января 2009

Итак, вопрос таков: что предпочтительнее, когда подклассифицирует абстрактный класс в Java и не хочет предоставлять реализацию?

a) пометить подкласс как абстрактный

b) пометить подкласс как абстрактный и переписать сигнатуру метода, помеченную как абстрактную?

Я бы пошел на первый:

a) Пометить подкласс как абстрактный.

В первом уже есть объявление абстрактного метода, повторять его нет смысла.

2 голосов
/ 06 января 2009

Перейти с # 1. Переписывание объявления метода в дочернем классе сбивает с толку. И вам действительно не нужны абстрактные методы в абстрактном классе, независимо от того, является ли родительский объект абстрактным или нет.

1 голос
/ 06 января 2009

Вы правы, оба случая эквивалентны. Случай 1) более прост, случай 2) - дублирование кода - избегайте его. Но для этого может быть одна причина:

Если метод в классе A не возвращает String, но, допустим, C, класс B может переопределить его (начиная с Java 5) с более конкретным типом возврата, скажем, D (класс расширяет C):

public abstract class A {
  public abstract C giveSum();
}

public abstract class B extends A {
  public abstract D giveSum();
}

public class C {
  ...
}

public class D extends C {
  ...
}
...