Einführung in die Erweiterung von Klassen in Java im Rahmen der Lehre des Programmierens mit der Programmiersprache Java. (statische Vererbung), Lektion, Seite 721557
http://www.purl.org/stefan_ram/pub/java_klassenerweiterungen_de ist die kanonische URI dieser Seite.
Stefan-Ram-Startseite

Klassen-Erweiterungen in Java

Eine Klasse kann eine direkte Erweiterung  einer anderen Klasse sein. Die der Erweiterung zugrundegelegte Klasse wird auch direkte Basisklasse  oder direkte Oberklasse  genannt.

Eine direkte Erweiterung  oder direkte Unterklasse  übernimmt die Einträge ihrer direkten Basisklasse und kann darüber hinaus noch weitere Einträge enthalten.

Da eine Klasse auch ein Typ ist, kann man auch von Obertypen  und Untertypen  sprechen.

Eine Erweiterung einer Basisklasse kann auch als eine Spezialisierung  dieser Basisklasse angesehen werden, weil sie noch spezielle Einträge hinzufügt. Umgekehrt kann eine Basisklasse einer Erweiterung auch als einer Verallgemeinerung  dieser Erweiterung angesehen werden.

Beispiel [UML class diagram]
.---------------------------------. 
| Basis | 
|---------------------------------| 
| - a : int | 
| --------- | 
|---------------------------------| 
| + pa() : void | 
| ------------- | 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung | 
|---------------------------------| 
| - b : int | 
| --------- | 
|---------------------------------| 
| + pb() : void | 
| ------------- | 
'---------------------------------'

Beispiel.java
class Basis 
{ private final static int a = 2;  
public static void pa(){ System.out.println( a ); }}
class Erweiterung extends Basis  
{ private final static int b = 4;  
public static void pb(){ System.out.println( b ); }}
public class Beispiel  
{ public static void main(String[] args)  
{ Erweiterung.pb();  
Erweiterung.pa(); }}

System.out

2

Man beachte, daß der Aufruf "Erweiterung.pa()" so erfolgt, als sei die Methode "pa" in der Klasse "Erweiterung" enthalten. Tatsächlich ist diese Methode "pa" aber in der Klasse "Basis" enthalten. Mithilfe des Schlüsselwortes "extends" wurde aber festgelegt, daß die Klasse "Erweiterung" eine Erweiterung der Klasse "Basis" darstellen soll.

Zugriffe auf Felder der direkten Basisklasse

Eine direkte Erweiterung kann nicht auf private Felder der direkten Basisklasse zugreifen

Beispiel2.java
class Basis 
{ private final static int a = 2; }
class Erweiterung extends Basis  
{ public static void pa(){ System.out.println( a ); }}
public class Beispiel2  
{ public static void main(String[] args)  
{ Erweiterung.pa(); }}

Konsole
Beispiel2.java:7: a has private access in Basis 
{ public static void pa(){ System.out.println( a ); }} 
^

Eine Klasse kann direkten Erweiterungen jedoch den Zugriff auf ihre Felder gestatten, ohne daß sie diese als öffentlich sichtbar deklarieren muß, indem sie den Feldmodifizierer "protected" verwendet. Ein so deklariertes Feld ist für die Methoden seines Pakets und für alle Methoden aller direkten Erweiterungen sichtbar. Es wird in UML  durch ein Doppelkreuz "#" gekennzeichnet.

Beispiel3 [UML class diagram]
.---------------------------------. 
| Basis | 
|---------------------------------| 
| # a : int | 
| --------- | 
|---------------------------------| 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung | 
|---------------------------------| 
|---------------------------------| 
| + p() : void | 
| ------------ | 
'---------------------------------'

Beispiel3.java
class Basis 
{ protected final static int a = 2; }
class Erweiterung extends Basis  
{ public static void p(){ System.out.println( a ); }}
public class Beispiel3  
{ public static void main(String[] args)  
{ Erweiterung.p(); }}

System.out
2

Man beachte auch, daß in der erweiternden Klasse "Erweiterung" der Eintrag "a" aus der Basisklasse "Basis" ohne weitere Eingrenzung verwendet werden kann. Es ist dort also nicht nötig, die Angabe "Basis.a" zu schreiben, vielmehr reicht die Angabe "a" aus, so als sei der Bezeichner "a" in der Klasse "Erweiterung" deklariert worden.

Es ist auch möglich, daß eine Erweiterung selber wieder erweitert wird. Die mit dem Feldmodifizierer "protected" deklarierten Felder einer Basisklasse sind auch in allen solchen indirekten Erweiterungen sichtbar.

Beispiel4 [UML class diagram]
.---------------------------------. 
| Basis | 
|---------------------------------| 
| # a : int | 
| --------- | 
|---------------------------------| 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung | 
|---------------------------------| 
| # b : int | 
| --------- | 
|---------------------------------| 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung1 | 
|---------------------------------| 
|---------------------------------| 
| + p() : void | 
| ------------ | 
'---------------------------------'

Beispiel4.java
class Basis 
{ protected final static int a = 2; }
class Erweiterung extends Basis 
{ protected final static int b = 4; }
class Erweiterung1 extends Erweiterung  
{ public static void p() 
{ System.out.println( a ); System.out.println( b ); }}
public class Beispiel4  
{ public static void main(String[] args)  
{ Erweiterung1.p(); }}

System.out

4

Wenn die Klasse "Erweiterung1" eine direkte Erweiterung der Klasse "Erweiterung" ist und die Klasse "Erweiterung" eine direkte Erweiterung der Klasse "Basis" ist, dann ist die Klasse "Erweiterung1" eine indirekte Erweiterung der Klasse "Basis". Die Klasse "Erweiterung" und die Klasse "Erweiterung1" sind Erweiterungen der Klasse "Basis".

Wenn es nicht nötig oder nicht erwünscht ist, zwischen direkter  und indirekter  Erweiterung zu unterscheiden, oder aus dem Zusammenhang entnommen werden kann, was gemeint ist, kann auch einfach nur von einer Erweiterung  gesprochen werden.

Eine Erweiterung einer Klasse "A " wird auch eine A -Klasse genannt.

Verdeckung eines Basisbezeichners

Ein schon in einer Basisklasse deklarierter Bezeichner kann in einer Erweiterung erneut deklariert werden. Er verdeckt  in der Erweiterung dann den Bezeichner der Basisklasse.

Beispiel5 [UML class diagram]
.---------------------------------. 
| Basis | 
|---------------------------------| 
| # a : int | 
| --------- | 
|---------------------------------| 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung | 
|---------------------------------| 
| # a : int | 
| --------- | 
|---------------------------------| 
| + p() : void | 
| ------------ | 
'---------------------------------'

Beispiel5.java
class Basis 
{ protected final static int a = 2; }
class Erweiterung extends Basis 
{ protected final static int a = 4;  
public static void p() 
{ System.out.println( a ); }}
public class Beispiel5 
{ public static void main(String[] args)  
{ Erweiterung.p(); }}

System.out
4

Der Zugriffschutz des Feldes in der erweiternden Klasse muß nicht mit dem Zugriffschutz des Feldes in der Basisklasse übereinstimmen.

Auch eine Methode kann verdeckt werden.

Beispiel6 [UML class diagram]
.---------------------------------. 
| Basis | 
|---------------------------------| 
|---------------------------------| 
| + p() : void | 
| ------------ | 
'---------------------------------' 

/_\ 


.---------------------------------. 
| Erweiterung | 
|---------------------------------| 
|---------------------------------| 
| + p() : void | 
| ------------ | 
'---------------------------------'

Beispiel6.java
class Basis 
{ public static void p() 
{ System.out.println( 9 ); }}
class Erweiterung extends Basis 
{ public static void p() 
{ System.out.println( 7 ); }}
public class Beispiel6 
{ public static void main(String[] args)  
{ Erweiterung.p(); }}

System.out
7

In einer Erweiterung kann allerdings unter ausdrücklicher Nennung einer Basisklasse auf eine verdecktes Feld dieser Basisklasse zugegriffen werden.

Beispiel7.java
class Basis 
{ protected final static int a = 2; }
class Erweiterung extends Basis 
{ protected final static int a = 4; }
class Erweiterung1 extends Erweiterung 
{ protected final static int a = 6;  
public static void p() 
{ System.out.println( a );  
System.out.println( Erweiterung.a );  
System.out.println( Basis.a ); }}
public class Beispiel7 
{ public static void main(String[] args)  
{ Erweiterung1.p(); }}

System.out


2

Zugriffsmöglichkeiten

Die folgenden Übersetzungseinheiten verwenden alle erlaubten Zugriffe (die mit ";;" gekennzeichnet wurden), während nicht erlaubte Zugriffe in Kommentaren angegeben sind.

p/K.java
package p;
public class K 
{ public static void pub(){ System.out.print( "public" ); } 
protected static void pro(){ System.out.print( "protected" ); } 
static void def(){ System.out.print( "(Vorgabe)" ); } 
private static void pri(){ System.out.print( "private" ); }}

p/Zugriff.java
package p;
public class Zugriff 
{ public static void main( String[] args ) 
{ ;; K.pub(); 
;; K.pro(); 
;; K.def(); 
/* K.pri(); */ }}

p/Zugriff1.java
package p;
public class Zugriff1 extends K 
{ public static void main( String[] args ) 
{ ;; pub(); 
;; pro(); 
;; def(); 
/* pri(); */ }}

Zugriff2.java
public class Zugriff2 
{ public static void main( String[] args ) 
{ ;; p.K.pub(); 
/* p.K.pro(); */ 
/* p.K.def(); */ 
/* p.K.pri(); */ }}

Zugriff3.java
public class Zugriff3 extends p.K 
{ public static void main( String[] args ) 
{ ;; pub(); 
;; pro(); 
/* def(); */ 
/* pri(); */ }}

A Zugriffsmöglichkeiten begründen
Geben Sie für jeden einzelnen Zugriff (auch für die Zugriffe in Kommentaren) an, warum dieser so möglich bzw. so nicht möglich ist.

Nutzen der Erweiterung

Es ist denkbar, daß bestimmte Einträge in mehreren Klassen in gleicher Form vorkommen.

Die Klasse "Sabine" und die Klasse "Peter" enthalten jeweils eine Deklaration einer Methode "hallo".

Beispiel8.java
class Sabine 
{ public static void hallo(){ System.out.print( "Hallo " ); } 
public static void gruesse() 
{ hallo(); System.out.println( "Sabine!" ); }}
class Peter  
{ public static void hallo(){ System.out.print( "Hallo " ); } 
public static void gruesse() 
{ hallo(); System.out.println( "Peter!" ); }}
public class Beispiel8 
{ public static void main(String[] args)  
{ Sabine.gruesse(); Peter.gruesse(); }}

System.out
Hallo Sabine! 
Hallo Peter!

[UML class diagram]
.--------------------------.     .--------------------------. 
| Sabine | | Peter | 
|--------------------------| |--------------------------| 
|--------------------------| |--------------------------| 
| + hallo() : void | | + hallo() : void | 
| ---------------- | | ---------------- | 
| + gruesse() : void | | + gruesse() : void | 
| ------------------ | | ------------------ | 
'--------------------------' '--------------------------'

Es ist redundant (wiederholend) die Methode "hallo" der Klasse "Peter" so zu deklarieren, daß ihre Deklaration einer Deklaration in einer anderen Klasse genau gleicht. Solche Redundanzen führen eher zu bestimmten Fehlern und erhöhen den Wartungsaufwand. Wünschenswert wäre es, die Methode nur einmal  zu definieren.

Hierzu kann nun eine Basisklasse eingesetzt werden, welche die sich wiederholende Deklaration nur einmal enthält und die dann von jeder bisherigen Klasse „importiert“ (erweitert) wird.

Beispiel9.java
class Person 
{ protected static void hallo(){ System.out.print( "Hallo " ); }}
class Sabine extends Person 
{ public static void gruesse() 
{ hallo(); System.out.println( "Sabine!" ); }}
class Peter extends Person 
{ public static void gruesse() 
{ hallo(); System.out.println( "Peter!" ); }}
public class Beispiel9 
{ public static void main( String[] args )  
{ Sabine.gruesse(); Peter.gruesse(); }}

System.out
Hallo Sabine! 
Hallo Peter!

[UML class diagram]
                 .--------------------------. 
| Person | 
|--------------------------| 
|--------------------------| 
| # hallo() : void | 
| ---------------- | 
'--------------------------' 

/_\ 

.----------------'----------------. 
| | 
| | 
.-----------'--------------. .------------'-------------. 
| Sabine | | Peter | 
|--------------------------| |--------------------------| 
|--------------------------| |--------------------------| 
| + gruesse() : void | | + gruesse() : void | 
| ------------------ | | ------------------ | 
'--------------------------' '--------------------------'

Eine wichtige Aufgabe einer Basisklasse ist es, Deklarationen für ihre Unterklassen bereitzustellen, die sonst in jeder Unterklasse wiederholt werden müssten.

Anwendung der Verdeckung einer Basisklassen-Methode

Wenn eine bestimmte Person anders, beispielsweise in Englisch, gegrüßt werden soll, dann kann eine Methode einer Basisklasse in der Klasse dieser Person durch eine Deklaration verdeckt werden.

BeispielA.java
class Person 
{ protected static void hallo(){ System.out.print( "Hallo " ); }}
class Sabine extends Person 
{ public static void gruesse() 
{ hallo(); System.out.println( "Sabine!" ); }}
class Peter extends Person 
{ protected static void hallo(){ System.out.print( "Hello " ); } 
public static void gruesse() 
{ hallo(); System.out.println( "Peter!" ); }}
public class BeispielA 
{ public static void main( String[] args ) 
{ Sabine.gruesse(); Peter.gruesse(); }}

System.out
Hallo Sabine! 
Hello Peter!

Die verdeckende Deklaration darf nicht mit schwächerem Zugriffschutz deklariert werden als die verdeckte Deklaration, deswegen wird die Methode "hallo" in der Klasse "Peter" mit dem Modifizierer "protected" deklariert.

[UML class diagram]
                 .--------------------------. 
| Person | 
|--------------------------| 
|--------------------------| 
| # hallo() : void | 
| ---------------- | 
'--------------------------' 

/_\ 

.----------------'----------------. 
| | 
| | 
.-----------'--------------. .------------'-------------. 
| Sabine | | Peter | 
|--------------------------| |--------------------------| 
|--------------------------| |--------------------------| 
| + gruesse() : void | | + gruesse() : void | 
| ------------------ | | ------------------ | 
'--------------------------' | # hallo() : void | 
| ---------------- | 
'--------------------------'

Von der Stefan-Ram-Startseite ausgehend finden sich oft noch mehr Informationen zu Themen, die auf einer Seite angesprochen wurden. (Eine Verbindung zur Stefan-Ram-Startseite befindet sich ganz oben auf dieser Seite.)  |   Seiteninformation und Impressum  |   Formular für diese Seite betreffende Mitteilungen an den Herausgeber  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. slrprd, PbclevtugFgrsnaEnz