Matroids Matheplanet Forum Index
Moderiert von matph
Informatik » Programmieren » Java: Sub- und Supertyp in Methoden
Druckversion
Druckversion
Autor
Universität/Hochschule J Java: Sub- und Supertyp in Methoden
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Themenstart: 2021-06-02


Hallo,
ist der von mir grün getextmarkerte Teilteil so richtig



oder müsste es nicht heißen: ...jeder Parametertyp von \(meth_{sub}\) muss ein Subtyp des entsprechenden Parametertyps von \(meth_{super}\) sein?



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.1, eingetragen 2021-06-02


Es ist so richtig, wie es da steht.

Die Submethode muss ja mit allen Eingabeparametern der Supermethode funktionieren.

PS.: Probiere es doch aus. :)


-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.2, vom Themenstarter, eingetragen 2021-06-02


Das verwirrt mich aber. Wenn die Sub-Methode mit allen Parametern der Super-Methode klarkommen muss und Subtypen vielleicht spezieller und komplizierter sind, dann würde ein Supertyp ja ggf. nicht ausreichen.

Subtypen enthalten doch mindestens das was die Supertypen enthalten, aber ggf. mehr.

Irgendwo hakt's noch.



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.3, vom Themenstarter, eingetragen 2021-06-02


Angenommen, die Supermethode sup-druck druckt von dem Typen
"Schüler" seinen Namen und die Schulklasse aus. Schüler sei dabei ein Subtyp von "Person".

Die Submethode sub-druck könnte dann "Personen" akzeptieren. Da wäre es aber nicht mehr möglich, die Schulklasse auszudrucken, wenn die Person kein Schüler ist.

Wo ist mein Denkfehler?



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.4, eingetragen 2021-06-02


2021-06-02 20:46 - curious_mind in Beitrag No. 3 schreibt:
Angenommen, die Supermethode sup-druck druckt von dem Typen
"Schüler" seinen Namen und die Schulklasse aus. Schüler sei dabei ein Subtyp von "Person".

Die Submethode sub-druck könnte dann "Personen" akzeptieren. Da wäre es aber nicht mehr möglich, die Schulklasse auszudrucken, wenn die Person kein Schüler ist.

Wo ist mein Denkfehler?

Wenn man sogar beliebige(!) Personen ausdrucken kann, kann man insbesondere auch Schüler ausdrucken.


-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.5, eingetragen 2021-06-03


Ich habe mal ein Beispiel gebastelt:
Java
  1. package OverloadParameter;
  2.  
  3. public class Main {
  4.  
  5. static class ParameterGrandParentType{
  6. }
  7. static class ParameterParentType extends ParameterGrandParentType{
  8. }
  9. static class ParameterChildType extends ParameterParentType{
  10. }
  11.  
  12. static class ParentPrinter{
  13. void print(ParameterParentType p){
  14. System.out.println("ParentPrinter prints " + p.getClass().getName());
  15. }
  16. }
  17.  
  18. static class ChildPrinter extends ParentPrinter{
  19. void print(ParameterChildType p){
  20. System.out.println("ChildPrinter prints " + p.getClass().getName());
  21. }
  22. }
  23.  
  24. static class GrandParentPrinter extends ParentPrinter{
  25. void print(ParameterGrandParentType p){
  26. System.out.println("GrandParentPrinter prints " + p.getClass().getName());
  27. }
  28. }
  29.  
  30. public static void main(String[] args){
  31. var grandparent = new ParameterGrandParentType();
  32. var parent = new ParameterParentType();
  33. var child = new ParameterChildType();
  34.  
  35. System.out.println("Using ParentPrinter:");
  36. var pp = new ParentPrinter();
  37. //pp.print(grandparent); // Not possible
  38. System.out.println("ParentPrinter cannot print GrandParentParameter.");
  39. pp.print(parent);
  40. pp.print(child);
  41.  
  42. System.out.println("\nUsing GrandParentPrinter:");
  43. var gp = new GrandParentPrinter();
  44. gp.print(grandparent);
  45. gp.print(parent);
  46. gp.print(child);
  47.  
  48. System.out.println("\nUsing ChildPrinter:");
  49. var cp = new ChildPrinter();
  50. //cp.print(grandparent); // Not possible
  51. System.out.println("ChildPrinter cannot print GrandParentParameter.");
  52. cp.print(parent);
  53. cp.print(child);
  54. }
  55.  
  56. }
  57.  
  58.  
  59. >> Output:
  60.  
  61. Using ParentPrinter:
  62. ParentPrinter cannot print GrandParentParameter.
  63. ParentPrinter prints OverloadParameter.Main$ParameterParentType
  64. ParentPrinter prints OverloadParameter.Main$ParameterChildType
  65.  
  66. Using GrandParentPrinter:
  67. GrandParentPrinter prints OverloadParameter.Main$ParameterGrandParentType
  68. ParentPrinter prints OverloadParameter.Main$ParameterParentType
  69. ParentPrinter prints OverloadParameter.Main$ParameterChildType
  70.  
  71. Using ChildPrinter:
  72. ChildPrinter cannot print GrandParentParameter.
  73. ParentPrinter prints OverloadParameter.Main$ParameterParentType
  74. ChildPrinter prints OverloadParameter.Main$ParameterChildType



-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.6, vom Themenstarter, eingetragen 2021-06-03


Beitrag obsolet



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.7, vom Themenstarter, eingetragen 2021-06-04


Hallo,

also, soweit ich sehe, hast du drei Typen in der Beziehung

Child < Parent < Grandparent erstellt,

und drei Druckerklassen in der Beziehung

ChildPrinter < ParentPrinter > GrandparentPrinter erstellt.

Und ich sehe, dass
- der ParentPrinter keinen Grandparent-Typ drucken kann,
- der GrandparentPrinter alles ausdrucken kann und
- der ChildPrinter Parent- und Child-Typen ausdrucken kann.

Allerdings bin ich irgendwie immer noch ratlos, was ich dem jetzt entnehmen soll...



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.8, eingetragen 2021-06-04


Vielleicht wäre es besser, wenn du mal genau angibst, was du erreichen möchtest.


Überschreibende Methoden müssen in Java exakt die gleichen Parametertypen besitzen wie die Überschriebenen.
Der Rückgabewert darf ein Subtype sein.

Von der reinen Vererbungslogik her könnten überschreibende Methoden auch Supertypen als Parameter besitzen und es finden sich sicherlich auch objektorientierte Programmiersprachen, die das erlauben. (Java wie gesagt nicht!)

Überschreibende Methoden können von der Vererbungslogik her jedoch niemals Supertypen als Rückgabetyp oder Subtypen als Parametertyp besitzen.


Beim Überladen ist beides möglich.
Es wird dann die als Spezifischste erachtete der möglichen Methoden ausgewählt. (beides ist in meinem Beispiel demonstriert)



-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.9, vom Themenstarter, eingetragen 2021-06-04


2021-06-04 12:10 - DerEinfaeltige in Beitrag No. 8 schreibt:
Vielleicht wäre es besser, wenn du mal genau angibst, was du erreichen möchtest.

Es geht nicht um irgendeine Aufgabe / Programm, sondern ich will den Text an der markierten Stelle verstehen.

2021-06-04 12:10 - DerEinfaeltige in Beitrag No. 8 schreibt:
Von der reinen Vererbungslogik her könnten überschreibende Methoden auch Supertypen als Parameter besitzen und es finden sich sicherlich auch objektorientierte Programmiersprachen, die das erlauben. (Java wie gesagt nicht!)

Das ist aber doch genau die Aussage im grün markierten Satz. Dass die Submethoden (überschreibende Methoden) einen Supertyp-Paramater der überschriebenen Methode haben müssen.

Und genau finde das ich kurios.

Sorry, vielleicht ist meine Frage nicht klar, weil ich das halt nicht verstehe und daher auch nicht weiß, wie ich meine Frage präziser ausdrücken könnte.




Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
tactac
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 15.10.2014
Mitteilungen: 2105
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.10, eingetragen 2021-06-04

\(\begingroup\)\(\newcommand{\sem}[1]{[\![#1]\!]} \newcommand{\name}[1]{\ulcorner#1\urcorner} \newcommand{\upamp}{\mathbin {⅋}}\)
Man kann sich die Super-/Subtyp-Beziehung auch so vorstellen, dass es implizit verwendete Konvertierungsfunktionen gibt: An Stellen, wo ein Element des Typs $A$ benötigt wird, kann man ein Element eines Subtyps $A'$ von $A$ angeben. Dieses wird dann implizit durch eine Funktion $a\colon A' \to A$ konvertiert.

Eine Methode $f'\colon A \to B'$ (hier mal nur mit einem Argument) darf deshalb eine Methode $f\colon A' \to B$ überschreiben, weil durch geeignete Komposition mit impliziten Konvertierungen das exakt übereinstimmende Interface herauskommt:
<math>
\begin{tikzcd}
A"\ar{r}{f}\ar[dashed]{d}[swap]{a}&B \\
A\ar{r}[swap]{f"}&B"\ar[dashed]{u}[swap]{b}
\end{tikzcd}
</math>
\(\endgroup\)


Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.11, vom Themenstarter, eingetragen 2021-06-06


(2021-06-04 14:57 - tactac in <a href=viewtopic.php?topic=254236&
<math>
\begin{tikzcd}
A"\ar{r}{f}\ar[dashed]{d}[swap]{a}&B \\
A\ar{r}[swap]{f"}&B"\ar[dashed]{u}[swap]{b}
\end{tikzcd}
</math>

Danke, das hilft mir das Grundprinzip zu verstehen.

Trotzdem bleibt bei mir die gleiche Frage zurück - ich versuche es mal ohne Code zu formulieren:

Angenommen ich habe Person P und Schüler S als Objekte, wobei P > S, also P ist Supertyp von S.

P habe die Attribute "name", "geb".
S habe die Attribute "name, "geb", "schulklasse".

Bezogen auf deine Grafik sei nun $f: S\longrightarrow X$ die Methode, die Name + Schulklasse des Schülers ausdruckt. ($X$ ist jetzt mal die Konsole).

Will ich jetzt $f$ durch eine Funktion $f': P\longrightarrow X$ überschreiben, wird S zu P konvertiert und dabei geht das Attribut "int schulklasse" verloren, denn P hat kein solches Attribut.

Entsprechend kann $f'$ ja nur schiefgehen.

Deshalb ist für mich nicht nachvollziehbar, wieso man einen Supertyp bei $f'$ zulassen (können) sollte, denn da gehen Informationen verloren, die die Ursprungsfunktion aber vielleicht benötigte.

Ist jetzt meine Frage klar genug?



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.12, eingetragen 2021-06-06


Zwei Beispiele:

Das originale Interface $f$ erwartet, dass man aus einem Argument vom Typ "Schüler" ein Resultat vom Typ "Name" berechnet.


Sei "Person" ein Supertyp von "Schüler" und "Vorname" ein Subtyp von "Name".

Eine abgeleitete Methode $f'$, die einer beliebigen "Person" einen "Vornamen" zuordnet, erfüllt dieses Interface.

Denn man kann ein Argument vom Typ "Schüler" zu einer "Person" verallgemeinern und man kann das Resultat vom Typ "Vorname" zu "Name" verallgemeinern.
Die Methode $f'$ ist also geeignet, einem "Schüler" einen "Namen" zuzuordnen.


Dass oder ob hier Informationen verloren gehen, spielt keine Rolle.


Oder mathematisch:
Wir haben ein Interface $g$, das erwartet, dass aus einer natürlichen Zahl eine reelle Zahl berechnet wird.

Eine Funktion $g'$, die jeder reellen Zahl eine rationale Zahl zuordnet, erfüllt dieses Interface, da sie nach wie vor aus jeder natürlichen Zahl eine reelle Zahl berechnet.



In beiden Fällen lassen sich die Typen weder beim Argument noch beim Rückgabewert vertauschen.


Beispiel:
Ein Interface, das als Argument eine beliebige "Person" erwartet, kann ich nicht als Methode implementieren, die ausschließlich "Schüler" verarbeiten kann und wenn das Ergebnis der "Vorname" sein soll, so reicht es nicht aus, wenn ich einen beliebigen "Name" zurückgebe.


-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
Fabi
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 03.03.2002
Mitteilungen: 4574
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.13, eingetragen 2021-06-06


Hi,

Beachte bitte auch, dass die reine Tatsache, dass etwas erlaubt ist, nicht heißt, dass es eine besonders gute Idee oder besonders sinnvoll ist. Wenn du nunmal die Klassenstufe deines Schülers ausgeben willst, macht es halt einfach keinen Sinn, stattdessen eine beliebige Person zu erwarten.
 
Die Regel sagt nur, dass der Compiler zufrieden ist, wenn du eine Person statt eines Schülers in deine abgeleitete Methode steckst; nicht dass du damit zwingend irgendetwas sinnvolles anfangen kannst.

Als Faustregel sollte man diese Regel auch ignorieren und die Interfaces beim Vererben gleichlassen, außer man hat einen sehr guten Grund dafür. Ich würde das Ändern eines Interfaces in einem Codereview schon als Code smell ansehen und sehr genau hinschauen, warum das notwending sein sollte.+

vG,
Fabi


-----------------
"There would be the mathematical equivalent of worldwide rioting." (P.C.)

Willst du Hamburg oben sehen, musst du die Tabelle drehen.



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.14, vom Themenstarter, eingetragen 2021-06-06


Ok @DerEinfaeltige, Du hast z.B.

<math>
\begin{tikzcd}
Schler\ar{r}{f}\ar[dashed]{d}[swap]{a}&Name \\
Person\ar{r}[swap]{f"}&Vorname\ar[dashed]{u}[swap]{b}
\end{tikzcd}
</math>

Das funktioniert, zumindest wenn man den Typen Name aus Vorname herstellen kann, etwa durch Name=Vorname+"". (Nebenbei: Kann das Java von alleine?)

Das funktioniert jetzt aber doch nur, weil du vom Schüler nichts originär "schulisches" zurückgibst, sondern "Name", etwas, das auch Personenobjekte besitzen.

Mein Beispiel sieht aber eher so aus:

<math>
\begin{tikzcd}
Schler\ar{r}{f}\ar[dashed]{d}[swap]{a}&Schulklasse\\
Person\ar{r}[swap]{f"}&???\ar[dashed]{u}[swap]{b}
\end{tikzcd}
</math>

Das geht ja offensichtlich nur, wenn man irgendeine Sub-Methode findet, die als Rückgabetyp einen Subtyp von Schulklasse ausgibt, von welchem man auf die Schulklasse schließen könnte, oder etwa nicht?

Also, wenn ich es richtig verstehe jetzt, dann muss über die eingangs grün markierte Bedingung im Text hinaus zusätzlich immer gesichert sein, dass Rückgabetyp f' > Rückgabetyp f.

Meine Zusammenfassung - bitte korrigieren, wenn falsch oder bestätigen:

Beim Überschreiben einer Methode $f$ (Overloading) mittels $f'$ gilt:
Das ist nur möglich, wenn
a) Argumenttyp von $f'$ >= Argumenttyp von $f$ (>= i.S.v. selber Typ oder Supertyp)
b) Rückgabetyp von $f'$ <= Rückgabetyp von $f$ (<= i.S.v. selber Typ oder Subtyp)
c) die Namen der beiden Methoden $f$ und $f'$ identisch sind
d) die Implementierung von $f'$ abgesehen von Namen, Argument- und Rückgabetypen kann beliebig (insbesondere komplett anders als die von $f$) sein.







[Die Antwort wurde nach Beitrag No.12 begonnen.]



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
zippy
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 24.10.2018
Mitteilungen: 2446
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.15, eingetragen 2021-06-06


2021-06-06 11:16 - curious_mind in Beitrag No. 14 schreibt:
Beim Überschreiben einer Methode $f$ (Overloading) mittels $f'$ gilt:

Hier geht es nicht um Overloading, sondern um Overriding.



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
DerEinfaeltige
Senior Letzter Besuch: in der letzten Woche
Dabei seit: 11.02.2015
Mitteilungen: 2928
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.16, eingetragen 2021-06-06


Noch ein Hinweis:
Die abgeleitete Funktion kann natürlich immer so definiert werden, dass sie mindestens so mächtig ist wie die Supermethode.
Sie kann die Supermethode ja als partielle Funktion nutzen.


$f: \text{Schueler} \to \text{Schulklasse}$

$f': \text{Person} \to \text{Schulklasse}$

\[f'(p) = \begin{cases}
f(p)~\textbf{if}~p~\text{instanceof Schueler} \\
\text{null}~\textbf{else} \\
\end{cases}\]


-----------------
Why waste time learning when ignorance is instantaneous?
- Bill Watterson -



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind
Aktiv Letzter Besuch: in der letzten Woche
Dabei seit: 10.11.2012
Mitteilungen: 482
Zum letzten BeitragZum nächsten BeitragZum vorigen BeitragZum erstem Beitrag  Beitrag No.17, vom Themenstarter, eingetragen 2021-06-06


Ah, cool. Okay, ich glaube die Theorie ist mir jetzt klar geworden.

Wenn ich am Kapitelende die Übungsaufgaben dann lösen soll.. sieht man sich dann wahrscheinlich wieder. :D

Danke für die Geduld wie immer!



Eine Notiz zu diese Forumbeitrag schreiben Notiz   Profil  Quote  Link auf diesen Beitrag Link
curious_mind hat die Antworten auf ihre/seine Frage gesehen.
curious_mind hat selbst das Ok-Häkchen gesetzt.
Neues Thema [Neues Thema]  Druckversion [Druckversion]

 


Wechsel in ein anderes Forum:
 Suchen    
 
All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest © 2001-2021 by Matroids Matheplanet
This web site was originally made with PHP-Nuke, a former web portal system written in PHP that seems no longer to be maintained nor supported. PHP-Nuke is Free Software released under the GNU/GPL license.
Ich distanziere mich von rechtswidrigen oder anstößigen Inhalten, die sich trotz aufmerksamer Prüfung hinter hier verwendeten Links verbergen mögen.
Lesen Sie die Nutzungsbedingungen, die Distanzierung, die Datenschutzerklärung und das Impressum.
[Seitenanfang]