В моих поисках для корректного схватывания Интерфейсных лучших практик я заметил объявления, такие как:
List<String> myList = new ArrayList<String>();
вместо
ArrayList<String> myList = new ArrayList<String>();
- К моему пониманию причины то, потому что это позволяет гибкость в случае, если однажды Вы не хотите реализовывать ArrayList, но возможно другой тип списка.
С этой логикой я настроил пример:
public class InterfaceTest {
public static void main(String[] args) {
PetInterface p = new Cat();
p.talk();
}
}
interface PetInterface {
public void talk();
}
class Dog implements PetInterface {
@Override
public void talk() {
System.out.println("Bark!");
}
}
class Cat implements PetInterface {
@Override
public void talk() {
System.out.println("Meow!");
}
public void batheSelf() {
System.out.println("Cat bathing");
}
}
Мой вопрос, я не могу получить доступ к batheSelf () метод, потому что он только существует для CAT. Это приводит меня полагать, что я должен только объявить от Интерфейса, если я только собираюсь использовать методы, объявленные в Интерфейсе (и не дополнительные методы от подкласса), иначе я должен объявить от Класса непосредственно (в этом CAT случая). Я корректен в этом предположении?
Когда есть выбор между ссылкой на объект через их интерфейс
или класс
, предпочтение следует отдавать первому, но только при наличии подходящего типа ].
Рассмотрим String
в качестве примера реализует
CharSequence
. Вы не должны просто слепо использовать CharSequence
вместо String
во всех случаях, потому что это лишит вас простых операций, таких как trim ()
, toUpperCase ( )
и т. Д.
Однако метод, который принимает String
только для того, чтобы заботиться о своей последовательности char
значений , должен использовать CharSequence
вместо этого, потому что это подходящий тип в данном случае. Фактически, это имеет место при замене (цель CharSequence, замена CharSequence)
в классе String
.
Другой пример - java.util.regex.Pattern
и его метод сопоставления Matcher (CharSequence)
. Это позволяет создать Matcher
из Pattern
не только для String
, но и для всех других CharSequence
, которые существуют.
Отличный пример в библиотеке, где должен был использоваться интерфейс
, но, к сожалению, не использовался, также можно найти в Matcher
: его appendReplacement
и appendTail
методы принимают только StringBuffer
. Этот класс был в значительной степени заменен его более быстрым родственником StringBuilder
, начиная с версии 1.5.
StringBuilder
не является StringBuffer
, поэтому мы не можем использовать первый с методами append…
в Matcher
. Однако оба они реализуют
Appendable
(также введено в 1.5). В идеале Matcher
метод append…
должен принимать любой добавляемый
, и тогда мы могли бы использовать StringBuilder
, а также все другой Добавляемый
доступен!
Итак, мы можем видеть, как , когда существует соответствующий тип , обращение к объектам через их интерфейсы может быть мощной абстракцией, но только если эти типы существуют. Если тип не существует, вы можете рассмотреть возможность определения одного из них, если это имеет смысл. В этом примере Cat
вы можете определить, например, интерфейс SelfBathable
. Затем вместо ссылки на Cat
вы можете принять любой объект SelfBathable
(например, Parakeet
)
Если нет смысла создавать новый type, то вы непременно можете ссылаться на него по его классу
.
Если существуют соответствующие типы интерфейсов, тогда параметры, возвращаемые значения и поля должны быть объявлены с использованием типов интерфейсов. Если вы приобретете привычку использовать типы интерфейсов, ваша программа станет намного более гибкой. Совершенно уместно ссылаться на объект классом, если не существует подходящего интерфейса.
Да, вы правы. Вы должны объявить как самый общий тип, предоставляющий методы, которые вы используете.
Это концепция полиморфизма .
Вы правы, но при необходимости вы можете сделать кастинг из интерфейса на нужного питомца. Например:
PetInterface p = new Cat();
((Cat)p).batheSelf();
Конечно, если вы попытаетесь привести питомца к собаке, вы не сможете вызвать метод batheSelf(). Он даже не скомпилируется. Поэтому, чтобы избежать проблем, вы могли бы иметь метод вроде этого:
public void bathe(PetInterface p){
if (p instanceof Cat) {
Cat c = (Cat) p;
c.batheSelf();
}
}
При использовании instanceof
вы убеждаетесь, что не попытаетесь заставить собаку искупать себя во время выполнения. Что приведет к ошибке.
Да, вы правы. Если в Cat реализован «PetInterface», вы можете использовать его в приведенном выше примере и легко добавлять больше видов домашних животных. Если вам действительно нужно быть специфичным для Cat, вам необходимо получить доступ к классу Cat.