2008-10-13 4 views
99

Любознательная вещь случается в Java, когда вы используете абстрактный класс для реализации интерфейса: некоторые из методов интерфейса могут быть полностью отсутствуют (т. Е. Не существует абстрактного объявления или реальной реализации), но компилятор не жалуется.Почему абстрактный класс, реализующий интерфейс, может пропустить объявление/реализацию одного из методов интерфейса?

Например, если интерфейс:

public interface IAnything { 
    void m1(); 
    void m2(); 
    void m3(); 
} 

следующий абстрактный класс получает Весело скомпилирован без предупреждения или ошибки:

public abstract class AbstractThing implements IAnything { 
    public void m1() {} 
    public void m3() {} 
} 

Можете ли вы объяснить, почему?

+0

Нельзя создать объект абстрактного класса. Итак, пока реализация не предусмотрена для абстрактного класса, объекты не могут быть созданы для IAnything. Так что это совершенно нормально для компилятора. Компилятор ожидает, что любой не абстрактный класс, который реализует IAnything, должен реализовать все методы, объявленные из IAnything. И так как нужно расширить и реализовать AbstractThing, чтобы иметь возможность создавать объекты, компилятор будет вызывать ошибку, если эта реализация не реализует методы IAnything, оставленные AbstractThing. – VanagaS 2017-03-19 06:25:36

+0

МОЖЕТ ЛИ МЫ ПРИЗЫВАТЬ, что «шаблон дизайна адаптера»? если мы сохранили m1, m2, m3 пустое тело в абстрактном классе. , тогда MyMainClass расширяет этот абстрактный класс, и я бы мог переопределить любой метод, который я хочу, Никакое принуждение не отменять все методы. Пожалуйста, советую! – 2018-01-06 20:04:18

ответ

130

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

Следуя вашему примеру, попробуйте сделать подкласс AbstractThing без реализации метода m2 и посмотреть, какие ошибки дает вам компилятор. Это заставит вас реализовать этот метод.

+0

Я думаю, что компилятор должен все же выдавать предупреждения относительно абстрактных классов, которые реализуют интерфейсы неполностью, просто потому, что тогда вам нужно искать 2 определения классов, а не 1, чтобы увидеть, что вам нужно в подклассе. Это ограничение языка/компилятора. – workmad3 2008-10-13 15:11:25

+3

Это не будет хорошей идеей, так как обычно может быть множество абстрактных классов, а «ложные» предупреждения скоро сокрушат вас, в результате чего вы пропустите «истинные» предупреждения. Если вы думаете об этом, ключевое слово «abstract» существует, чтобы сказать компилятору, чтобы он подавил предупреждения для этого класса. – belugabob 2008-10-13 15:16:25

30

Отлично отлично.
Вы не можете создавать абстрактные классы. Но абстрактные классы могут использоваться для размещения общих реализаций для m1() и m3().
So если m2() реализация различна для каждой реализации, но m1 и m3 нет. Вы могли бы создавать различные конкретные реализации IAnything с помощью только разной реализации m2 и выводить из AbstractThing - соблюдая принцип DRY. Проверка целостности интерфейса для абстрактного класса бесполезна.

Обновление: Интересно, что я считаю, что C# принудительно применяет это как ошибку компиляции. Вы вынуждены копировать подписи метода и приписывать их абстрактному базовому классу в этом сценарии .. (что-то новое повседневное :)

1

Абстрактные классы не требуются для реализации методов. Таким образом, хотя он реализует интерфейс, абстрактные методы интерфейса могут оставаться абстрактными. Если вы попытаетесь реализовать интерфейс в конкретном классе (т. Е. Не абстрактный), и вы не реализуете абстрактные методы, которые компилятор вам скажет: либо реализуйте абстрактные методы, либо объявите класс абстрактным.

2

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

5

Это хорошо. Чтобы понять вышеизложенное, вы должны сначала понять природу абстрактных классов. В этом отношении они аналогичны интерфейсам. Об этом говорит Oracle об этом here.

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation.

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

//Filename: Sports.java 
public interface Sports 
{ 
    public void setHomeTeam(String name); 
    public void setVisitingTeam(String name); 
} 

//Filename: Football.java 
public interface Football extends Sports 
{ 
    public void homeTeamScored(int points); 
    public void visitingTeamScored(int points); 
    public void endOfQuarter(int quarter); 
} 

... как вы можете видеть, это также отлично компилируется. Просто потому, что, подобно абстрактному классу, интерфейс НЕ может быть создан. Таким образом, не требуется явно указывать методы из своего «родителя». Однако ВСЕ сигнатуры родительского метода DO неявно становятся частью расширяющегося интерфейса или реализуют абстрактный класс. Таким образом, как только правильный класс (тот, который может быть создан), расширяет вышесказанное, требуется, чтобы был реализован каждый абстрактный метод.

Надеюсь, что это поможет ... и Аллаху алам!

2

When an Abstract Class Implements an Interface

In the section on Interfaces, it was noted that a class that implements an interface must implement all of the interface's methods. It is possible, however, to define a class that does not implement all of the interface's methods, provided that the class is declared to be abstract. For example,

abstract class X implements Y { 
    // implements all but one method of Y 
} 

class XX extends X { 
    // implements the remaining method in Y 
} 

In this case, class X must be abstract because it does not fully implement Y, but class XX does, in fact, implement Y.

Ссылка: http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

1

Учитывая интерфейс:

public interface IAnything { 
    int i; 
    void m1(); 
    void m2(); 
    void m3(); 
} 

Это хо ж Java на самом деле видит:

public interface IAnything { 
    public static final int i; 
    public abstract void m1(); 
    public abstract void m2(); 
    public abstract void m3(); 
} 

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

При implementinterface, правило, что все interface методы должны быть реализованы в производном class, относится только к конкретному class реализации (то есть, что не является сам по себе abstract).

Если вы действительно планируете создание abstract class из него, то нет никакого правила, которое говорит, что вы, чтобы implement все interface методы (заметим, что в таком случае является обязательным объявить производный class как abstract)

Смежные вопросы