Действующий пункт Java 19 — только использование интерфейсов для определения типов

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

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

Пример:

public interface A{
    public void meth1();
}

public interface B{
    public void meth2();
}

public abstract class C implements A,B{

}

public void DynamicBinding(A aobject){
  //Can only call aobject.meth1();
}

person user997112    schedule 28.07.2012    source источник
comment
Я не понимаю вашего вопроса. Динамическое связывание очень тесно связано с полиморфизмом. На самом деле, я думаю, что это два термина, обозначающие почти одно и то же.   -  person Code-Apprentice    schedule 29.07.2012
comment
Я говорю о том, что я не могу использовать интерфейсы для создания подтипов, потому что мне нужно использовать методы из обоих интерфейсов в полиморфной переменной. Поэтому можно ли использовать абстрактный класс для создания подтипов, а затем интерфейсы используются только для того, чтобы убедиться, что методы реализованы? Это противоречит пункту 19.   -  person user997112    schedule 29.07.2012


Ответы (3)


Когда вам нужны методы только из A, тогда A можно использовать в качестве типа объекта, как вы проиллюстрировали. Аналогично для B. Если вам нужны методы из обоих, вы создаете новый интерфейс:

public interface C extends A, B {
}

Интерфейсам разрешено extend более одного интерфейса.

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

public abstract class D implements C {
  // implementation details
}
person Code-Apprentice    schedule 28.07.2012
comment
А как насчет моего абстрактного класса, который уже содержит методы для обоих? Вот почему я подумал, что можно использовать абстрактный класс для создания подтипов? - person user997112; 29.07.2012
comment
Можете ли вы включить абстрактный класс в вопрос, чтобы мы могли увидеть ваше предложение. - person Håvard Geithus; 29.07.2012
comment
@HåvardGeithus Я случайно забыл включить абстрактное определение класса C. Теперь оно есть... - person user997112; 29.07.2012
comment
@HåvardGeithus Интерфейс в моем примере устраняет необходимость в абстрактном классе, если вы не хотите дополнительно расширить пример, чтобы предоставить его с реализацией по умолчанию. Это еще одна проблема. - person Code-Apprentice; 29.07.2012
comment
@user997112 user997112 Если вы хотите последовать предложению по программированию интерфейса, вам следует сделать то, что я предложил в своем ответе. Оттуда вы можете предоставить реализацию по умолчанию с абстрактным классом (назовите его D), если хотите. Вы по-прежнему будете использовать интерфейс C в качестве типа для параметров и переменных. - person Code-Apprentice; 29.07.2012
comment
Да, я знаю. Меня смутило только то, что исходный постер ссылался на какой-то абстрактный класс, которого не было в вопросе :) - person Håvard Geithus; 29.07.2012
comment
@HåvardGeithus Вы имеете в виду какой-то абстрактный класс, которого не было в ответе? - person Code-Apprentice; 29.07.2012
comment
Нет. Он отредактировал вопрос, так что теперь он включает ключевое слово abstract для класса C. Раньше этого не было. - person Håvard Geithus; 29.07.2012
comment
@HåvardGeithus ааа ... я видел только отредактированную версию. Отсюда и путаница с моей стороны в этом разговоре. - person Code-Apprentice; 29.07.2012
comment
Есть ли причина, по которой вы приняли этот ответ, но не проголосовали за него? - person Code-Apprentice; 10.09.2012

Вы можете использовать дженерики, чтобы ваш метод принимал параметр как типа A, так и B:

public <T extends A & B> void method(T param) {
  param.meth1(); // fine
  param.meth2(); // also fine
}

Связанный вопрос здесь

person Jorn    schedule 28.07.2012
comment
Разве это не будет иметь тот же эффект, что и передача субинтерфейса C Code-Guru в качестве параметра типа для метода? - person Håvard Geithus; 29.07.2012
comment
Для этого одного примера, да. Однако у этого решения есть и другие преимущества, например, вам не нужно создавать подынтерфейс, и оно также будет работать, если первым параметром является класс (а не интерфейс). - person Jorn; 29.07.2012
comment
Итак, если бы это был класс, интерпретировались бы расширения как реализации? (Java не допускает множественного наследования). - person Håvard Geithus; 29.07.2012
comment
Нет, для синтаксиса <T extends ...>, как для методов, так и для классов, он всегда расширяется. Они все равно в основном одно и то же. - person Jorn; 29.07.2012

Вы могли бы сделать

public void DynamicBinding(C cobject){
  c.meth1();
  c.meth2();
}

или чуть худший вариант

public void DynamicBinding(A aobject){
if(aobject instanceof C)
      {
          C myC=(C)aobject;
          myC.meth1();
          myC.meth2();

      }
}

во всяком случае мне нравится то, что Йорн сделал больше.

person m0s    schedule 28.07.2012