Posługując się interfejsem, sprawiasz że nie obchodzi Cię konkretna implementacja danego zachowania tylko fakt, że jakiś obiekt przejawia dane zachowanie.
Jeżeli dana metoda działa na polu danej klasy, to przed jej wywołaniem musisz mieć utworzony dany obiekt (inaczej dostaniesz NPE). W tym przypadku, najlepiej się posługiwać dependency injection i podczas tworzenia obiektu danej klasy, podać konkretną implementację interfejsu.
W sytuacji gdy argumentem metody jest obiekt typu interfejsowego (type of an interface) to problem się rozwiązuje w zasadzie sam.
Korzystając z interfejsów, obchodzi Cię jedynie to że dany obiekt przejawia jakieś zachowanie (obiekt implementuje metodę). Dopiero podczas testowania/uruchamiania aplikacji musisz mieć zapewnioną implementację zachowania tworząc konkretny obiekt.
Ale gdzie tu ten wymóg używania wszystkich nazw metod z interfejsu? Kursy mówią o tym, że jak implementujesz interfejs musisz zrobić przepis, dać logikę, implementację wszystkich metod które się w nim znajdują.
Wymóg wprowadza kompilator. Jeżeli uważasz, że jakaś klasa powinna zaimplementować dany interfejs, ale nie "powinna" mieć jakiejś metody tzn, że twój interfejs łamie zasadę Single Responsibility. W sytuacji, gdy masz interfejs ale często implementacje tej metody będą takie same, możesz posłużyć się defaultowymi metodami.