Überschreiben von Exemplarmethoden beim Erweitern in Java (Überschreiben von Exemplarmethoden beim Erweitern in Java), Lektion, Seite 722843
https://www.purl.org/stefan_ram/pub/ueberschreiben_exemplarmethoden_java (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram

Ersetzen von Exemplarmethoden beim Erweitern in Java 

Exemplarmethoden, die bereits von einer Oberklasse übernommen wurden, können in einer Deklaration einer Unterklasse erneut deklariert werden.

Um auszudrücken, daß eine Methode zu jedem Exemplar einer Klasse gehören soll, wird die Methode ohne das Schlüsselwort »static« deklariert.

Dadurch wird eine eventuell vererbte Methode für die deklarierte Klasse (hier: »Main«) durch die neu deklarierte Methode ersetzt.

Main.java

public final class Main extends java.awt.geom.Point2D.Double
{

public static void main( final java.lang.String[] args )
{ final Main coordinate = new Main();
coordinate.y = 4;
coordinate.x = 3;
java.lang.System.out.println( coordinate.toString() );
java.lang.System.out.println( coordinate ); }}

transcript
Point2D.Double[3.0, 4.0]
Point2D.Double[3.0, 4.0]
Main.java

public final class Main extends java.awt.geom.Point2D.Double
{

public final java.lang.String toString()
{ return "Main"; }

public static void main( final java.lang.String[] args )
{ final Main coordinate = new Main();
coordinate.y = 4;
coordinate.x = 3;
java.lang.System.out.println( coordinate.toString() );
java.lang.System.out.println( coordinate ); }}

transcript
Main
Main
override ” (JLS3 8.4.8)
„überschreiben“, „aufheben“, „überlagern“ (nach dem „Handbuch der Java -Programmierung“ von Guido Krüger )
coordinate ” (Aussprache des Substantivs)
coordinate /ko ˈɔɚ dɪ nət/

Die Signatur einer ersetzenden Methodendeklaration muß der Signatur der ersetzen Methode gleichen.

Der Rückgabetyp  muß ein Untertyp  des Rückgabetyps der ersetzten Methode sein (“covariant return type ” [ˌkəʊˈveɚɪənt]).

Zu einer Exemplarmethode einer Oberklasse darf in einer Unterklasse keine statische  Methode mit gleicher Signatur deklariert werden.

Das Objekt »coordinate« wird erst als ein passiver Datensatz behandelt und an die Methode »println« übergeben. Diese Methode „aktiviert“ das Objekt dann, indem sie dessen »toString«. Methode aufruft. Hier zeigt sich wieder die Doppelnatur des Objektes als einerseits Datenspeicher und andererseits Akteur gleichzeitig.

Die Markierungsannotation »@java.lang.Override«

Die einfachste Form einer Annotation ist eine Markierungsannotation. Sie besteht nur aus einem kommerziellen À »@« und einem Namen.

Mit der Annotation »@java.lang.Override« kann gekennzeichnet werden, daß eine Methodendeklaration eine Methode eines Obertyps ersetzen  soll. Ein Compiler kann dann prüfen, ob dies wirklich erfolgt. Dadurch wird es verhindert, daß das Implementieren einer abstrakten Methode wegen eines kleinen Schreibfehlers im Namen der Methode unbemerkt scheitert. Diese Annotation kann vor  die Deklaration einer Methode geschrieben werden.

Die Dokumentation einer solchen Annotation kann unter der Dokumentation des Typs »java.lang.Override« in der schon bekannten Java-SE -API-Dokumentation nachgelesen werden.

Ein Beispiel zur Annotation »@java.lang.Override«

In dem folgenden Beispiel wird eine Methode »tostring()« deklariert. Wir wollen einmal annehmen, daß eigentlich die Methode »toString()« deklariert werden sollte, welche schon im Obertyp »java.lang.Object« vorkommt. Der Fehler könnte aber mangels einer Fehlermeldung unbemerkt bleiben.

Main.java

public final class Main
{ public java.lang.String tostring(){ return "alpha"; }

public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new Main() ); }}

java.lang.System.out
Main@27fa232

In dem nun folgenden Beispiel wurde die Deklaration der Methode »tostring()« mit »@java.lang.Override« gekennzeichnet. Dadurch wird erklärt, daß sie eine Methode eines Obertyps ersetzen soll. Da der Compiler erkennt, daß sie dies nicht tatsächlich tut, kann er nun den Fehler melden.

Main.java

public final class Main
{ @java.lang.Override public java.lang.String tostring(){ return "alpha"; }

public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new Main() ); }}

Konsole
Main.java:34: error: method does not override or implement a method from a supertype
{ @java.lang.Override public java.lang.String tostring(){ return "alpha"; }
Konsole (auf deutsch)
Main.java:34: Fehler: Methode ersetzt oder implementiert keine Obertypmethode
{ @java.lang.Override public java.lang.String tostring(){ return "alpha"; }
Aussprachehinweise
supertype ˈsupɚ ˈtaɪp

In dem folgenden Beispiel wurde der Fehler dann korrigiert. Nun ersetzt die Deklaration die Methode des Obertyps »java.lang.Object«.

Main.java

public final class Main
{ @java.lang.Override public java.lang.String toString(){ return "alpha"; }

public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new Main() ); }}

java.lang.System.out
alpha

Das Zurückschreiben in die Oberklasse

Wenn eine Methode eines Ausdrucks aufgerufen wird, dann wird zur Laufzeit die entsprechende Methode des Objektes aufgerufen, welches zu diesem Zeitpunkt der Wert des Ausdrucks ist. Dadurch kommt es zu dem erstaunlichen Phänomen, daß die Bedeutung von Aufrufen einer Oberklasse „nachträglich“ geändert werden kann. Wir sprechen hier auch vom „Zurückschreiben “ in eine Oberklasse, ein Begriff der nicht allgemein üblich ist, aber dem Autor ist kein allgemein üblicher Begriff für dieses spezielle Phänomen bekannt.

Main.java

class Base
{ void greet()
{ java.lang.System.out.println( "Hallo, " + name() + "." ); }

java.lang.String name()
{ return "Ben"; }}

final class Sub extends Base
{ @java.lang.Override
java.lang.String name()
{ return "Mia"; }}

public final class Main
{ public static void main( final java.lang.String[] args )
{ { final Base object = new Base(); object.greet(); }
{ final Base object = new Sub(); object.greet(); }}}

transcript
Hallo, Ben.
Hallo, Mia.

Wenn man sich nur die Klasse »Base« anschaut, so könnte man denken, daß »name()« immer »Ben« ergibt. Doch bei Objekten einer Unterklasse muß dies nicht mehr stimmen, dort wird dann die Methode »name()« der Unterklasse  aufgerufen. In gewissem Sinne hat damit die Unterklasse die Bedeutung des Aufrufs »name()« in einer Methode der Oberklasse verändert! Deswegen sprechen wir hier von „Zurückschreiben“.

Das Verhindern des Zurückschreibens

Wenn Unterklassen Methoden überschreiben, kann dies also auch die Funktion nicht-überschriebener Methoden der Oberklasse beeinträchtigen. Falls dies nicht erwünscht ist, kann das Überschreiben mit »final« für eine Methode verhindert werden. Wenn man eine Klasse mit »final« deklariert, dann verhindert man damit, daß überhaupt Unterklassen angelegt werden.

Die Warnung Joshua Blochs

(Dieser Abschnitt wurde noch nicht vollständig ausformuliert!)

Es ist nicht dokumentiert, daß java.util.HashSet bei addAll wieder add aufruft, weil dies als interne Implementationsentscheidung angesehen wird.

Main.java

class CountSet extends java.util.HashSet
{ /* based on an idea by Joshua Bloch */

private int count = 0;

public CountSet() {}

public boolean add( final java.lang.Object object )
{ ++count;
return super.add( object );}

public boolean addAll( final java.util.Collection collection )
{ count += collection.size();
return super.addAll( collection ); }

public int getCount()
{ return CountSet.this.count; }}

public final class Main
{ public static void main( final java.lang.String[] args )
{ final CountSet set = new CountSet();
set.addAll( java.util.Arrays.asList( new java.lang.String[] { "a", "b", "c" }));
java.lang.System.out.println( set.getCount() ); }}

Protokoll
6

Item 15: Design and document for inheritance or else prohibit it

Statisches Verdecken

Main.java

final class Other
{

public static void method()
{ java.lang.System.out.println( "Other.method()" ); }}

public final class Main
{

public static void method()
{ java.lang.System.out.println( "Main.method()" ); }

public static void main( final java.lang.String[] args )
{ method();
Main.method();
Other.method(); }}

Protokoll
Main.method()
Main.method()
Other.method()
Main.java

class Other
{

public static void method()
{ java.lang.System.out.println( "Other.method()" ); }}

public final class Main extends Other
{

public static void method()
{ java.lang.System.out.println( "Main.method()" ); }

public static void main( final java.lang.String[] args )
{ method();
Main.method();
Other.method(); }}

Protokoll
Main.method()
Main.method()
Other.method()

Statisches Verdecken bei Feldern

Felder werden nicht wie Methoden ersetzt, sondern lediglich (statisch) „verdeckt“.

Main.java

class A { int x = 3; }

class B extends A { int x = 7; }

public final class Main
{

public static void main( final java.lang.String[] args )
{

final A a0 = new A();

final A a1 = new B();

final B b0 = new B();

java.lang.System.out.println( a0.x );

java.lang.System.out.println( a1.x );

java.lang.System.out.println( b0.x );

java.lang.System.out.println( ( ( A )b0 ).x ); }}

transcript

3

3

7

3

Übungsfrage

Aussprache „Basenschi“

Main.java

class Hund
{ public static void bell()
{ java.lang.System.out.print( "Wau" ); }}

final class Basenji extends Hund
{ public static void bell() {} }

public final class Main
{ public static void main( final java.lang.String[] args )
{ final Hund leo = new Hund();
final Hund max = new Basenji();
leo.bell();
max.bell(); }}

Protokoll
WauWau

 

 

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722843 stefan_ram:722843 Überschreiben von Exemplarmethoden beim Erweitern in Java Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722843, slrprddef722843, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/ueberschreiben_exemplarmethoden_java