abstrakte Klasse implementiert ein Interface

ernst

Top Contributor
Hallo allerseits,
Folgender Fall:
Die abstrakte Klasse Tier implementiert die Schnittstelle IDruck mit dem Methodenkopf print().
Das bedeutet eigentlich, dass print() eine abstrakte Methode ist und in der Klasse Tier ausprogrammiert werden muss.
Da Tier aber eine abstrakte Klasse ist und print() eine abstrakte Methode ist, darf print() in Tier nicht ausprogrammiert werden
Es müsste also im folgenden Programm eine Fehlermeldung geben.
Dem ist aber nicht so.
Warum ?

mfg
Ern

Java:
[/B]
package testabstractinterface10;

public class Startklasse {
    public static void main(String[] args) {
    }
}


abstract class Tier implements IDruck{
    private String name;
    public void print(){
        System.out.println("Name="+name);
    }

}
[B]

Hier das Interface:

Java:
[/B]
package testabstractinterface10;
public interface IDruck {
    void print();
}
[B]
 
Die abstrakte Klasse Tier implementiert die Schnittstelle IDruck mit dem Methodenkopf print().
Das bedeutet eigentlich, dass print() eine abstrakte Methode ist
Nicht zwangsläufig. Was an der abstrakten Klasse tatsächlich abstrakt ist, das bestimmst du selbst (mit dem Schlüsselwort abstract vor der jeweiligen Methode). Es kann also durchaus sein (und ist vermutlich auch nicht unüblich), dass das Interface in der abstrakten Klasse implementiert wird, z.B.
Java:
interface Printable {
    void print();
}

abstract class AbstractPrintable implements Printable {

    // Implementation des Interfaces
    @Override
    public void print() {
        System.out.println("Dieser Text wird immer gedruckt. Der nachfolgende kommt von der Kindklasse: ");
        doPrint();
    }

    // abstrakte Methode, die von den Kindklassen überschrieben werden muss
    protected abstract void doPrint();
}
 
Zuletzt bearbeitet:
>
>Nicht zwangsläufig. Was an der abstrakten Klasse tatsächlich abstrakt ist,
>das bestimmst du selbst (mit dem Schlüsselwort abstract vor der jeweiligen Methode).
>
Wenn Tier nicht abstrakt ist, dann müsste print() ausprogrammiert werden. Also ist print() in dieser Hinsicht abstrakt.
Deine Argumentation widerspricht der Meinigen.
Wo wird entschieden wer Recht hat ?
Doku ?

mfg
Ern
 
Wenn Tier nicht abstrakt ist, dann müsste print() ausprogrammiert werden.
In deinem Beispiel ganz oben ist die Methode print() ausprogrammiert. Das hat mit der als abstrakt gekennzeichneten Klasse nichts zu tun. Die Klasse lässt sich nur nicht instantiieren (weil sie abstrakt ist).

Also ist print() in dieser Hinsicht abstrakt.
Nein!

EDIT: Du kannst durchaus eine abstrakte Klasse programmieren, die keine einzige abstrakte Methode hat und damit voll funktionsfähig wäre. Allerdings lassen sich, wie oben schon geschrieben, abstrakte Klassen nicht instantiieren. Du musst dazu immer eine (oder mehrere) entsprechende Kindklasse erstellen, um Instanzen davon zu erzeugen.

Sobald allerdings eine abstrakte Methode in der Klasse existiert, muss die gesamte Klasse als abstract gekennzeichnet werden.

In deiner gezeigten Klasse sind keine abstrakten Methoden deklariert. Das erkennst du auch daran, dass die Methode print() einen Methodenkörper hat (die geschweiften Klammern). Sogar ein leerer Methodenkörper wäre eine Implementation (die halt nichts tut).
 
Zuletzt bearbeitet:
Gibt es eine Möglichkeit, den Programmierer zu zwingen, daß man in der Klasse Tier die Methode print() ausprogrammieren muß?
Evtl. durch Einführung von Unterklassen von Nutztier ?

mfg
Ern
 
Gibt es eine Möglichkeit, den Programmierer zu zwingen, daß man in der Klasse Tier die Methode print() ausprogrammieren muß?
Evtl. durch Einführung von Unterklassen von Nutztier?
Mir ist nicht ganz klar, was du erreichen möchtest.

Richtig zwingen kann man m.M.n. nicht, denn auch die Kindklasse einer abstrakten Klasse kann wieder eine abstrakte Klasse sein, die eben diese Methode nicht implementiert.
 
Mir ist nicht ganz klar, was du erreichen möchtest.

Richtig zwingen kann man m.M.n. nicht, denn auch die Kindklasse einer abstrakten Klasse kann wieder eine abstrakte Klasse sein, die eben diese Methode nicht implementiert.
Ich will erreichen, dass ein evtl. unaufmerksamer Programmierer gezwungen wird, eine Methode auszuprogrammieren, weil sonst der Compiler einen Fehler bringt. Und das geht meines Wissens mit abstrakten Methoden bzw. Interfaces.

mfg
Ern
 
Dann solltest du die Methode "print" in der Klasse Tier eben nicht implementieren:
Java:
abstract class Tier implements IDruck{
    private String name;
}
// bzw...
abstract class Tier implements IDruck{
    private String name;
    public abstract void print();
}
 
Dann solltest du die Methode "print" in der Klasse Tier eben nicht implementieren:
Java:
abstract class Tier implements IDruck{
    private String name;
}
// bzw...
abstract class Tier implements IDruck{
    private String name;
    public abstract void print();
}

Ich will, dass der Programmier gezwungen wird, die Methode print() in der Klasse Tier auszuprogrammieren.
Das leistet dein Vorschlag nicht.

mfg
Ern
 
Ich will erreichen, dass ein evtl. unaufmerksamer Programmierer gezwungen wird, eine Methode auszuprogrammieren
Auf den konkreten Fall bezogen: Meinst du den unaufmerksamen Programmierer, der die Klasse "Tier" programmiert oder den, der die Kindklasse von "Tier" programmiert?

Die Lösung für den zweiten Fall hat dir @CSHW89 bereits genannt: Du darfst die Methode aus dem Interface in der abstrakten Klasse Tier einfach nicht implementieren.
 
Ich will erreichen, dass ein evtl. unaufmerksamer Programmierer gezwungen wird, eine Methode auszuprogrammieren, weil sonst der Compiler einen Fehler bringt. Und das geht meines Wissens mit abstrakten Methoden bzw. Interfaces.
Zum letzten Satz: jein. Natürlich wird spätestens die Klasse, von der eine Instanz erzeugt wird, die Methode implementieren müssen. Du kannst aber niemanden daran hindern, zuvor erneut eine abstrakte abgeleitete Klasse zu erstellen, in der die Methode nicht implementiert wird.

Der erste Satz ist ein Widerspruch in sich. Du willst den Programmierer dazu zwingen. Und wer setzt das durch? Richtig, der Compiler. Du willst also einen Compilerfehler durch einen Compilerfehler verhindern. Gibt jetzt nicht wirklich Sinn.
 
Wer sagt außerdem, dass es eine Klasse Tier überhaupt geben muss? Der Programmierer kann ja jederzeit eine beliebige Klasse erstellen, die das Interface implementiert.
 
Wer sagt außerdem, dass es eine Klasse Tier überhaupt geben muss? Der Programmierer kann ja jederzeit eine beliebige Klasse erstellen, die das Interface implementiert.
Gegegen ist:
die abstrakte Klasse Tier.

Behauptung:
Es gibt keine Möglichkeit, einen Programmier zu zwingen die Methode print() in Tier auszuprogrammieren.
Unter zwingen verstehe ich: Wenn die Methode nicht in Tier ausprogrammiert wird, soll der Compiler eine Fehlermeldung bringen.

Frage:
Ist meine Behauptung richtig?

mfg
Ern
 
Das geht nicht. Wenn eine Klasse abstrakt ist, müssen die Methoden auch nicht ausprogrammiert werden.

Aber diese ganze Diskussion ist sinnlos. Man gibt mit einem Interface oder einer abstrakten Klasse eine Schnittstelle vor. Wer dann konkrete Klassen ableitet musst die fehlenden Reste der Schnittstelle implementieren. Von vorneherein Vorgaben zu machen, was genau man machen muss in Ableitungen und wie die Ableitungen strtukturiert werden (ob Abstrakt oder nicht) ist weder möglich noch sinnvoll oder zielführend.
 
Mach dich mal frei von dem Interface und der abstrakten Klasse und versuche zu beschreiben, was du erreichen möchtest.

Was ist dein konkreter Anwendungsfall?

Vielleicht gibt es ja eine Lösung dafür, abseits von dem bisher geschriebenen.
 
Abgesehen davon: wenn die Klasse gegeben ist, muss der Programmierer ja nichts mehr programmieren.
Was ja durchaus ein Grund für abstrakte Klassen ist: Man gibt dem Programmierer eine Basis zur Hand, die bereits Teile der Lösung umsetzt, so das er weniger Arbeit hat, die vollständige Funktionalität bereitzustellen. Siehe dazu auch die Klassen in der Java Bibliothek: z.B. List<> ➡ AbstractList<>
 
Was ja durchaus ein Grund für abstrakte Klassen ist: Man gibt dem Programmierer eine Basis zur Hand, die bereits Teile der Lösung umsetzt, so das er weniger Arbeit hat, die vollständige Funktionalität bereitzustellen. Siehe dazu auch die Klassen in der Java Bibliothek: z.B. List<> ➡ AbstractList<>
Du hast mich falsch verstanden. Wenn die Klasse Tier gegeben ist, muss der Programmierer in Klasse Tier nichts mehr programmieren 🙂

"Gegegen ist: die abstrakte Klasse Tier. [...] Wenn die Methode nicht in Tier ausprogrammiert wird, soll der Compiler eine Fehlermeldung bringen."
 
Du hast mich falsch verstanden. Wenn die Klasse Tier gegeben ist, muss der Programmierer in Klasse Tier nichts mehr programmieren 🙂

"Gegegen ist: die abstrakte Klasse Tier. [...] Wenn die Methode nicht in Tier ausprogrammiert wird, soll der Compiler eine Fehlermeldung bringen."
Das hatte ich auch so verstanden. Ich wollte nur noch einen sinnvollen Anwendungsfall für gegebene abstrakte Klassen nennen.
 
print() muß nicht in Tier implementiert werden:
Java:
package testabstractinterface10;
public class Startklasse {
    public static void main(String[] args) {
        Tier [] tiere = new Tier[1];
        tiere[0]=new Kuh("Milka", 100);
        tiere[0].print();
    }
}

abstract class Tier implements IDruck{
    protected String name;

    public Tier(String name){
        this.name=name;
    }
}

class Kuh extends Tier implements IDruck{
    private int gewicht;

    public Kuh(String name, int gewicht){
        super(name);
        this.gewicht=gewicht;
    }

    public void print(){
        System.out.println("Name="+name+" gewicht="+gewicht);
    }
}

Soweit ist alles ok.
Aber warum meckert der Compiler, wenn man in der Klasse Tier print() nicht ausprogrammiert ?

Java:
package testabstractinterface10;

public class Startklasse {

    public static void main(String[] args) {
        Tier [] tiere = new Tier[1];
        tiere[0]=new Kuh("Milka", 100);
        tiere[0].print();
    }
}

abstract class Tier{    
    protected String name;

    public Tier(String name){
        this.name=name;
    }
}

class Kuh extends Tier implements IDruck{
    private int gewicht;

    public Kuh(String name, int gewicht){
        super(name);
        this.gewicht=gewicht;
    }

    public void print(){
        System.out.println("Name="+name+" gewicht="+gewicht);
    }
}

mfg
Ern
 
Mal ganz einfach: ein Interface deklariert eine Schnittstelle, d. h. eine Menge öffentlicher Methoden. Eine Klasse kann diese Schnittstelle implementieren. Das bedeutet nicht zwangsläufig, dass die Methoden der Schnittstelle in dieser Klasse auch implementiert werden müssten, sondern, dass Instanzen der Klasse oder einer von ihr abgeleiteten Klassen über diese Methoden verfügen. Ein "implements X" kann man übersetzen zu "ist nach Spezifikation X verwendbar".

Somit bedeutet class Tier implements IDruck nichts anderes als, dass jedes Objekt von Tier (oder einer von Tier abgeleiteten Klasse) so verwendbar ist, wie es in IDruck spezifiziert wurde. Jedes Tier-Objekt ist also nach Spezifikation von IDruck verwendbar.

Da Du von abstrakten Klassen keine Instanzen erzeugen kannst, muss die Methode in diesen auch nicht ausprogrammiert werden.
 
Mal ganz einfach: ein Interface deklariert eine Schnittstelle, d. h. eine Menge öffentlicher Methoden. Eine Klasse kann diese Schnittstelle implementieren. Das bedeutet nicht zwangsläufig, dass die Methoden der Schnittstelle in dieser Klasse auch implementiert werden müssten, sondern, dass Instanzen der Klasse oder einer von ihr abgeleiteten Klassen über diese Methoden verfügen.
Was ebdeutet dann "dass Instanzen der Klasse oder einer von ihr abgeleiteten Klassen über diese Methoden verfügen" konkret, wenn sie nicht in der Klasse ausprogrammiert werden müssen ? Was meinst du dann mit "verfügen" ?

mfg
Ern
 
Was bedeutet dann "dass Instanzen der Klasse oder einer von ihr abgeleiteten Klassen über diese Methoden verfügen" konkret, wenn sie nicht in der Klasse ausprogrammiert werden müssen ? Was meinst du dann mit "verfügen" ?
Irgendwo muss die Methode natürlich ausprogrammiert werden, spätestens, wenn eine Instanz erzeugt werden soll. Dazu muss es nicht einmal eine unmittelbare Klasse geben, wenn man z.B. die Instanz einer anonymen Klasse erzeugt
Java:
public class Main {

    public static void main(String[] args) {

        // "printer" ist vom Typ IDruck und verfügt damit über die Methode print()
        // auch wenn die im Interface noch nicht ausprogrammiert ist.
        IDruck drucker;
       
        // Hier wird der Variablen die Instanz einer anonymen Klasse zugewiesen.
        // Spätestens jetzt, muss die Methode implementiert werden.
        drucker = new IDruck() {
            @Override
            public void print() {
                System.out.println("Ich bin eine anonyme Klasse, die auch druckt.");
            }
        };

        drucker.print();
    }
}
 
Um die Methode "print" einer Variablen des Typs "IDruck" aufzurufen, benötigst du eine Instanz einer Klasse, die IDruck implementiert und die die Methode "print" als vollständige Implementierung besitzt.

- Irgendeine Klasse, die IDruck nicht implementiert spielt keine Rolle
- Eine abstrakte Klasse (die IDruck implementiert) kann nicht instantiiert werden, daher muss "print" nicht implementiert werden. Die erste Bedingung ist nicht erfüllt, daher muss der Compiler die zweite auch nicht sicherstellen.
- Eine konkrete Klasse (die IDruck implementiert) muss "print" implementieren, da sie instantiiert werden kann. Dies muss der Compiler bei der Definition der Klasse bereits sicherstellen, damit ein Aufruf von "print" auf einer "IDruck"-Variablen funktioniert.
 
Um die Methode "print" einer Variablen des Typs "IDruck" aufzurufen, benötigst du eine Instanz einer Klasse, die IDruck implementiert und die die Methode "print" als vollständige Implementierung besitzt.

- Irgendeine Klasse, die IDruck nicht implementiert spielt keine Rolle
- Eine abstrakte Klasse (die IDruck implementiert) kann nicht instantiiert werden, daher muss "print" nicht implementiert werden. Die erste Bedingung ist nicht erfüllt, daher muss der Compiler die zweite auch nicht sicherstellen.
- Eine konkrete Klasse (die IDruck implementiert) muss "print" implementieren, da sie instantiiert werden kann. Dies muss der Compiler bei der Definition der Klasse bereits sicherstellen, damit ein Aufruf von "print" auf einer "IDruck"-Variablen funktioniert.
Gut erklärt, ich schlage vor die Bedeutung den Wortes "implementiert" zur Klarheit noch zu trennen (auch wenn die Begriffe synonym verwendet werden können):

implementiert = implements (eine Klasse mit dem Schlüsselwort implements)
ausprogrammiert = hier wird die implementierte Methode tatsächlich in Code umgesetzt.

- Irgendeine Klasse, die IDruck nicht implementiert spielt keine Rolle. Ergänzung: Es sei denn, sie ist die Kindklasse einer Klasse, die IDruck implementiert und ausprogrammiert hat (siehe auch nächster Punkt).
- Eine abstrakte Klasse, die IDruck implementiert, kann nicht instantiiert werden, daher muss print() nicht ausprogrammiert werden. Die erste Bedingung ist nicht erfüllt, daher muss der Compiler die zweite auch nicht sicherstellen. Ergänzung: Die abstrakte Klasse kann allerdings print() ausprogrammieren. In dem Fall erben die davon abgeleiteten Kindklassen sowohl die implementierte Schnittstelle, als auch die ausprogrammierte Methode.
- Eine konkrete Klasse, die IDruck implementiert, muss print() ausprogrammieren, da sie instantiiert werden kann. Dies muss der Compiler bei der Definition der Klasse bereits sicherstellen, damit ein Aufruf von print() auf einer "IDruck"-Variablen funktioniert.
 
Java:
interface Foo {
    void doSomething();
}

class Bar {
    void doSomething() {
        // irgendein Code...
    }
}

Foo foo = new Bar(); // Fehler! Bar implementiert nicht Foo, auch wenn es über (irgend)ein doSomething() verfügt.
Java:
interface Foo {
    void doSomething();
}

class Bar implements Foo {
    @Override
    public void doSomething() {
        // irgendein Code...
    }
}

Foo foo = new Bar(); // Passt!
foo.doSomething(); // Passt!
Java:
interface Foo {
    void doSomething();
}

abstract class AbstractBar implements Foo {
    // die Methode muss hier nicht ausprogrammiert werden, weil die Klasse abstrakt ist
}

Foo foo = new AbstractBar(); // Fehler! Abstrakte Klasse kann nicht instantiiert werden.

class Bar extends AbstractBar {
    // Hier muss die Methode ausprogrammiert werden, weil eine Instanz erzeugt werden kann
    // und noch keine Ausprogrammierung der Methode vorliegt.
    @Override
    public void doSomething() {
        // irgendein Code...
    }
}

Foo foo = new Bar(); // Passt!
foo.doSomething();

class AnotherBar extends Bar {

}

Foo foo = new AnotherBar(); // Passt! AnotherBar erbt sowohl die Schnittstelle, als auch die Ausprogrammierung von Bar
foo.doSomething();
Java:
interface Foo {
    void doSomething();
}

abstract class AbstractBar implements Foo {
    // die Methode kann hier ausprogrammiert werden
    @Override
    public void doSomething() {
        // irgendein Code...
    }
}

Foo foo = new AbstractBar(); // Fehler! Abstrakte Klasse kann nicht instantiiert werden.

class Bar extends AbstractBar {
    // Hier muss die Methode nicht mehr ausprogrammiert werden, sie wurde von AbstractBar geerbt
}

Foo foo = new Bar(); // Passt!
foo.doSomething();
 
Danke für die vielen konketen Beispiele.
Man könnte noch den Fall bringen, wenn
void doSomething()
in einer abstrakten Klasse als abstrakte Methode deklariert wird.

mfg
Ern
 
Java:
interface Foo {
    void doSomething();
}

abstract class AbstractBar {
    // die Methode muss hier nicht ausprogrammiert werden, weil sie abstrakt ist
    public abstract void doSomething();
}

Foo foo = new AbstractBar(); // Fehler! Abstrakte Klasse kann nicht instantiiert werden.

class Bar extends AbstractBar {
    // Hier muss die Methode ausprogrammiert werden, weil eine Instanz erzeugt werden kann
    // und noch keine Ausprogrammierung der Methode vorliegt.
    @Override
    public void doSomething() {
        // irgendein Code...
    }
}

Foo foo = new Bar(); // Fehler! Weder AbstractBar noch Bar implementieren Foo
 
abstract class AbstractBar {
// die Methode muss hier nicht ausprogrammiert werden, weil sie abstrakt ist
public abstract void doSomething();
}

besser:
// die Methode darf hier nicht ausprogrammiert werden, weil sie abstrakt ist
 
abstract class AbstractBar {
// die Methode muss hier nicht ausprogrammiert werden, weil sie abstrakt ist
public abstract void doSomething();
}

besser:
// die Methode darf hier nicht ausprogrammiert werden, weil sie abstrakt ist
Das hängt von der Sichtweise ab. Die Methode wurde ja als abstrakt gekennzeichnet, damit sie nicht ausprogrammiert werden muss.
 

Zurück
Oben