Интерфейс Java как ссылочный тип?

Где я должен использовать интерфейс как тип переменной? Я вижу, что многие люди говорят, что это лучше всего, но каждый пример относится к коллекциям:

List<String> list = new ArrayList<>()

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

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

Himanshu Bhardwaj 06.08.2018 12:31

Для Java 10 и более поздних версий рассмотрите возможность использования var для локальных переменных.

Thorbjørn Ravn Andersen 06.08.2018 12:31

См. Это stackoverflow.com/questions/6643136/…

DhaRmvEEr siNgh 06.08.2018 12:34
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
1 276
5

Ответы 5

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

Поэтому используйте только ArrayList с new. Используйте List везде. (Если у вас нет на то веской причины)

Примечание. Для Java 10 вы можете использовать синтаксис var для локальных переменных:

var list = new ArrayList<String>();

Даже без алмаза <>?

GhostCat 06.08.2018 12:49

@GhostCat да.

snr 06.08.2018 12:50

@GhostCat да - тогда используется Object. В этом случае необходима строка. Спасибо, что указали на это.

Thorbjørn Ravn Andersen 06.08.2018 13:00

Сказать здесь спасибо ... поскольку ваш ответ вдохновил на этот новый вопрос ;-)

GhostCat 06.08.2018 13:07

Использование интерфейсов лучше, чем конкретные классы, потому что это проще, если вы хотите переключить реализацию. Но это применимо только в том случае, если у вас есть выгода от этого; использование List вместо ArrayList в методе из 5 строк не сильно меняет ваш код. Преимущество больше, когда вы получаете их как ссылку на метод или конструктор, потому что вы используете интерфейс / контракт, и «пользователь» вашего кода (это может быть вы) может легко передать другую реализацию для улучшения программы или как имитацию в тест.

Для ввода-вывода довольно часто работают с InputStream и OutpuStream, конкретный тип - на усмотрение пользователя. Так что вы можете использовать InputStream для чтения либо из сети, либо из локального файла.

Рекомендуется ссылаться на интерфейс, потому что таким образом вы всегда можете изменить фактическую реализацию без каких-либо изменений в вызывающей стороне этого интерфейса. Предположим, у вас есть среда CDI, такая как Spring. У вас может быть ServiceInterface с несколькими реализациями, но контроллер никогда не увидит фактическую реализацию.

Контроллер:

@Controller
public class MyController {

    @Autowired
    private ServiceInterface service;

    /*stuff*/
}

ServiceInterface:

public interface ServiceInterface{ /*stuff*/ }

Реализация «А»:

@Service
@Profile("A")
@Primary
public class ServiceImplementationA implements ServiceInterface {
     /*stuff*/
}

Реализация «Б»:

@Service
@Profile("B")
public class ServiceImplementationB implements ServiceInterface {
    /*stuff*/
}

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

Это своего рода дальнозоркость. Да, есть правило,

Always code to interface.

Но почему?

Вы используете new ArrayList<>() для типа определения и List<String> для декларативного типа. Это хорошая практика. Теперь давайте подумаем, как правило, для nonce производительность ArrayList действительно подходит для ваших данных и программы. Что делать, если существует новый тип контейнера, например называется NicePerformedList, который также реализует интерфейс List и значительно улучшает производительность вашей программы через 5 лет. Будете ли вы проводить рефакторинг всех декларативных типов вместо простого изменения типа определения?

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

interface MathInterface{

int sum();


}  

class A implements MathInterface
{
@Override
int sum()
{

//implementation
}

}
class B implements MathInterface
{
@Override
int sum()
{

//implementation
}

}

class Main
{

MathInterface mathInterface=new B();

doSomeThing(mathInterface);


} 

Другие вопросы по теме