Jeśli implementuję interfejs, to czy nazywa się to dziedziczeniem?

31

Jeśli moja klasa implementsjest interfejsem, to czy mogę powiedzieć, że śledzę dziedziczenie? Wiem, że kiedy klasa jest extendsinną klasą, to jest to dziedzictwo.

RajeeV VenkaT
źródło
7
Komentarz Jodrella jest po prostu błędny. Implementacja interfejsu jest w rzeczywistości dziedziczeniem, a dziedziczenie jednego interfejsu od drugiego jest dziedziczeniem. Skąd wiemy? Definiując słowo, którego używamy. Dziedziczenie jest właściwością polegającą na tym, że dziedziczeni członkowie jednego typu są również członkami innego typu. Według tej definicji, po prostu klasa, która implementuje interfejs, odziedziczyła wszystkie metody interfejsu; wystarczy spojrzeć na klasę i interfejs, a przekonasz się, że we właściwym programie mają oni tych samych członków.
Eric Lippert
Nie zaznaczyłem i pozostawiłem więcej zamieszania.
RajeeV VenkaT
18
Wydaje mi się, że warto poświęcić dużo czasu na definicję słów, która nie przyniesie wiele korzyści. Ostatecznie wszyscy wiemy, co oznacza implementacja interfejsu i czy uważa się go za „dziedziczenie”, jest w dużej mierze nieistotne w codziennej pracy.
Robert Harvey
3
Ja (głównie) zgadzam się z Robertem. Uważam, że zrozumienie dokładnego technicznego znaczenia słów żargonowych, które są używane w różnych kontekstach, ma prawdziwą wartość. Ale Robert ma rację, że zrozumienie praktycznego wpływu przynosi znacznie większe korzyści! Jak wykorzystać dziedziczenie, aby twój kod był bezpieczniejszy? Bardziej testowalny? Bardziej wielokrotnego użytku? Bardziej elastyczne? I tak dalej. Wiedza, że ​​członkowie typów podstawowych są również członkami typów pochodnych, jest świetna, ale lepiej jest nadal wiedzieć, jak skutecznie z niej korzystać.
Eric Lippert,

Odpowiedzi:

78

AKTUALIZACJA: Poprawiłem tę odpowiedź. Podkreślono wiele dobrych punktów w komentarzach, które zasługiwały na odwołanie.

Jeśli moja klasa implementuje interfejs, czy mogę powiedzieć, że śledzę dziedziczenie?

Nie jest do końca jasne, co rozumiesz przez „podążanie za spadkiem”. Zadajmy nieco inne pytanie?

Co to jest dziedziczenie?

  • Kiedy członkowie jednego typu X są uważane za członków innego typu Y, ci członkowie Y są dziedziczone od X .
  • Istnieje związek dziedziczenia między niektórymi typami; to znaczy dla niektórych typów X i Y mówimy „Y dziedziczy po X”.

Te są subtelnie różne. To niefortunne, ponieważ jest mylące.

Jakie nieporozumienia zwykle wynikają z tego subtelnego rozróżnienia?

Może pojawić się zamieszanie, ponieważ ludzie myślą o dziedziczeniu jako mechanizmie udostępniania szczegółów implementacji. Chociaż jest to taki mechanizm, mechanizm ten działa poprzez udostępnianie członków . Ci członkowie nie muszą mieć wdrożeń! Jak zobaczymy, mogą być abstrakcyjne.

Osobiście byłbym szczęśliwszy, gdyby specyfikacje Java i C # używały słowa innego niż „dziedziczy” do opisania związku między metodami interfejsu i klasami, aby uniknąć tego zamieszania. Ale nie robią tego i musimy uzasadniać na podstawie specyfikacji, a nie przeciwko nim.

Czy w Javie członkowie interfejsu są dziedziczeni przez klasy, które je implementują?

Tak, niektóre są. Zobacz specyfikację Java w sekcji 8.4.8, którą cytuję tutaj dla Twojej wygody.

Klasa C dziedziczy po swojej bezpośredniej nadklasie i bezpośrednich super interfejsach wszystkie abstrakcyjne i domyślne metody m, dla których spełnione są wszystkie poniższe warunki: [...]

Jeśli powiesz, że klasa implementuje interfejs, klasa dziedziczy abstrakcyjne i domyślne metody tego interfejsu . (Oczywiście pominąłem następujące warunki; zobacz szczegóły w specyfikacji. W szczególności nie uważa się , że klasa, która implementuje element interfejsu, odziedziczyła ten element. Ponownie, czy to jest mylące? Tak.)

Czy zazwyczaj mówimy w Javie, że klasa dziedziczy po interfejsie?

Zazwyczaj powiedzielibyśmy, że klasa implementuje interfejs. Jak wspomniano powyżej, klasa może dziedziczyć elementy po interfejsie, a mimo to nie można powiedzieć, że dziedziczy po interfejsie. Co jest mylące, tak.

Czy to subtelne rozróżnienie ma znaczenie w codziennej pracy?

Zazwyczaj nie. Tego rodzaju wąskie analizowanie specyfikacji jest bardziej przydatne dla autorów kompilatorów niż dla programistów biznesowych. Ważniejsze jest, aby zrozumieć, kiedy używać interfejsu, niż uzyskać dokładną definicję „dziedziczy po”.

Eric Lippert
źródło
4
Nie mogę się kłócić kanonicznym odniesieniem. Kiedy specyfikacje różnią się, tak jak muszą, proste terminy stają się semantycznie przeciążone i niejednoznaczne z kontekstu. Pytanie jest oznaczone tagiem, javawięc jest to prawidłowa odpowiedź, chyba że OP oznaczało inne java:-)
Jodrell
5
Chociaż pytanie jest oznaczone Javą, trudno jest cytować specyfikację języka dla ogólnego terminu. Wiele języków ma interfejsy, a ich specyfikacje językowe mogą używać innego terminu, więc użycie terminu specyficznego dla Javy może być mylące podczas rozmowy z programistami używającymi X-Lang.
Thomas Owens
5
@ThomasOwens: Zgadzam się, że ten scenariusz jest powszechny i ​​całkowicie nie zgadzam się z twoim wnioskiem. Rozwiązaniem problemu komunikacyjnego, który opisujesz, jest uświadomienie wszystkim zaangażowanym, jakie są dokładne znaczenia słów w odpowiednim kontekście . Istnieją specyfikacje zapewniające tę przejrzystość; Użyj ich!
Eric Lippert
5
Dlaczego specyfikacja języka Java ma tak decydujące znaczenie? Specyfikacja języka często twierdzi, że „zwykły programista” nie zgadza się z terminologią.
Benjamin Gruenbaum
5
@BenjaminGruenbaum: Nie wiem. Ci programiści się mylą i często biorą na siebie odpowiedzialność za „edukowanie” innych co do ich błędnych przekonań. Nie uwierzyłbyś w liczbę książek o języku programowania, które musiałem naprawić, ponieważ autorzy mieli całkowicie szalone przekonania na temat VB, C #, JavaScript itp., Które nie były w żaden sposób poprawne. (Jon Skeet nie był wśród nich; C # w głębi było poprawne od samego początku! Nigdy nie zrobiłem tak niewielu komentarzy na temat książki i nadal otrzymywałem zapłatę.)
Eric Lippert
26

Dziedziczenie oznacza napisanie nowej podklasy dla nadklasy. Pisanie nowej klasy przeciwko interfejsowi implementuje ten interfejs. (A pisanie nowego interfejsu opartego na starym rozszerza ten interfejs).

Jedynym poprawnym terminem, który dotyczy wszystkich trzech możliwości, jest podtyp . Nie każdy podtyp jest podklasą.

Kilian Foth
źródło
1
Wydaje się, że książka GoF uważa dziedziczenie interfejsu za odpowiedni termin do opisywania podtypów (Rozdział 1.6 Klasa a dziedziczenie interfejsu)
komnata
„Kiedyś uczestniczyłem w spotkaniu grupy użytkowników Java, w którym wystąpił James Gosling (wynalazca Javy). Podczas niezapomnianej sesji pytań i odpowiedzi ktoś zapytał go:„ Jeśli mógłbyś ponownie zrobić Javę, co byś zmienił? ”„ pomiń klasy ”, odpowiedział. Wyjaśnił, że prawdziwym problemem nie były same klasy, ale raczej dziedziczenie implementacji (relacja rozszerza). Preferowane jest dziedziczenie interfejsu (relacja implementacji). Powinieneś unikać dziedziczenia implementacji, gdy tylko jest to możliwe.” javaworld.com/article/2073649/core-java/…
ricardoramos
1

Z podklasami ty

  • odziedziczyć stan nadklasy (wszystkie zmienne instancji, niezależnie od tego, czy je widzisz)
  • dziedzicz rzeczywiste implementacje (wszystkie metody nieabstrakcyjne)

Dzięki interfejsom wypełniasz umowę, wdrażając zadeklarowane metody.

To klasyczny sposób patrzenia na to. Teraz w Javie 8 interfejsy stają się mieszanką:

  • nadal nie dziedziczysz stanu (ponieważ interfejsy wciąż nie mają zmiennych instancji)
  • teraz możesz dziedziczyć domyślne implementacje z interfejsu

Czy wdrożenie interfejsu, którego metody mają wszystkie implementacje domyślne, nadal liczy się jako „implement”, czy raczej jako rozszerzenie? Nie mogłem powiedzieć Ponieważ ten przypadek jest dość daleko posunięty (to faktycznie włączyło bezpaństwowe wielokrotne dziedziczenie), nadal używałbym „dziedziczenia” tylko z podklasami.

Peter Walser
źródło