# Lieber von JFrame erben?



## DerAlk (24. Okt 2011)

Hallo,

ich würde gerne wissen, welche Vorteile das erben von der Klasse JFrame hat.
Persönlich schöner finde ich es nämlich, wenn man ein JFrame erzeugt und diesem dann die Komponenten hinzufügt.
Was meint ihr bzw. wie macht ihr es?


----------



## Marco13 (24. Okt 2011)

Spontan-subjektiv: Keine. Ich kann mir kaum vorstellen, wann man das machen sollte.


----------



## Gast2 (24. Okt 2011)

Ich könnte mir auch keine Szenarien vorstellen wo man unbedingt von nem JFrame erben sollte.



> Persönlich schöner finde ich es nämlich, wenn man ein JFrame erzeugt und diesem dann die Komponenten hinzufügt.


Ganz genau.


----------



## thE_29 (24. Okt 2011)

In meiner Schulzeit wurde auch immer davon abgeraten von JFrame zu erben..

Der alte Prof. hatte aber die Eigenart dann die Klasse von JPanel (=mainpanel) erben zu lassen und dort halt dann drauf die Komponenten zu adden und das ganze dann aufs JFrame..

Ob das jetzt soviel mehr Sinn hatte.. Man könnte halt in die paint-Methoden oder sonstigen eingreifen, aber tjo.. Wenn mans nicht braucht, hats nicht wirklich Vorteile..


----------



## DerAlk (24. Okt 2011)

Vielen Dank für die schnellen Einschätzungen.
Habe hier nämlich gerade ein Buch vor mir liegen, wo das so gemacht wird. Aber dann möchte ich mir das gar nicht erst angewöhnen.


----------



## Camino (24. Okt 2011)

Aber gibt es auch einen Grund oder Nachteile, warum man das nicht machen sollte?


----------



## Gast2 (24. Okt 2011)

Klar, du kannst nur von einer Klasse erben. Wenn du also schon von JFrame erbst hast du keine Möglichkeit mehr von ner anderen Klasse zu erben.
Man sollte imho Komposition immer der Vererbung vorziehen, falls man nicht unbedingt das Verhalten der Klasse ändern bzw. erweitern will.

Von JFrame erben macht mMn nie sinn. Von JPanel eigentlich nur wenn man die paintComponent Methode überschreiben will.


----------



## SlaterB (24. Okt 2011)

wer will schon je in einer JFrame-Klasse von etwas anderem erben? 
oder selbst wenn ist es immer leicht umzubauen und spätestens bei der zweiten Vererbung hätte man dasselbe Problem, nix gewonnen,
zweimal Vererbung klingt komisch? genauso auch nur eine Vererbung bei JFrame..

das ist bisschen unsauber aber einfach nur eine Kleinigkeit, macht 1-x frame.xy()-Aufrufe leichter,
JFrames hat man üblicherweise nur 1x oder wenn dann je JFrame eine Klasse die sich darum kümmert, die nach außen gerne auch wie ein JFrame aussehen darf um z.B. setVisible(true) aufzurufen, 
genauso mehrere JPanel-Klassen für größere Sub-Strukturen


```
SubPanelXy a = new SubPanelXy();
add(a);
```
schreibt sich schöner als 

```
SubPanelXy a = new SubPanelXy();
this.frame.add(a.getPanel());
```

immer eine Gratwanderung, an anderen Stellen würde ich auch nicht etwa von ArrayList erben,
aber in GUIs ist das schon ziemlich handlich und übersichtlich


----------



## noobadix (24. Okt 2011)

Vielleicht kann man das Risiko, Methoden versehentlich zu überschreiben, als Nachteil sehen.
Und: Wie ist das mit Threads? Wenn JFrame nicht threadsicher ist, wie ist es dann mit Threads, die in dem Objekt erzeugt werden? (Vielleicht offenbart die Fragestellung schon, dass ich mich damit nicht auskenne, is nur so'n Gedanke ^^ )


----------



## SlaterB (24. Okt 2011)

im Grunde exakt dasselbe aus meiner Sicht, wobei ich persönlich so gut wie nie irgendeine Thread-Methode brauche, dann geht Runnable,
wenn man aber interrupt(), join(), isAlive() usw. abfragen will und eine Klasse hat die 'für diesen Thread' steht, also normalerweise eh von nichts zu erben hat, dann könnte diese von Thread erben, statt den Thread extra in einem Attribut stehen zu haben


----------



## Marco13 (24. Okt 2011)

Die Frage nach Threads ist eigentlich orthogonal dazu. Ein "hartes" Gegenargument kann ich spontan nicht nennen, aber ... was sollte in einer Klasse stehen, damit sie von JFrame erben muss? Oder damit es einen Vorteil bringt? Für welches "X" gilt "X _ist ein_ JFrame"? 
Grenzfälle könnte es geben, wenn man z.B. eine komplizierte Toolbar einbauen will oder viel mit anderen JFrame-eigenen Methoden rumhantiert oder so, aber auch das ist kein echter Grund. Und wenn es keinen driftigen Grund gibt, sollte man nicht Vererben.


----------



## André Uhres (24. Okt 2011)

Ehe Swing eingeführt wurde, machte es keinen Sinn von "Frame" zu erben. Jetzt erbt "JFrame" von "Frame" und inzwischen sogar "JXFrame" von "JFrame" (SwingX library). Es macht offenbar nur Sinn, wenn Du eine grundlegende und allgemein gültige Idee hast, wie Du einen Frame noch intelligenter machen kannst als eine bestehende Klasse.

Gruß,
André


----------



## DerAlk (24. Okt 2011)

Hier in diesem Tutorial/Beispiel ab Schritt 4 wird das gemacht.

JFrame

Also ist es im Prinzip schlechter Stil.


----------



## SlaterB (24. Okt 2011)

wozu wird überhaupt ein Objekt der Klasse HalloWelt erstellt, könnten doch alle Befehle in der main-Methode stehen..

das letzte Programm auf der Seite zeigt, wie 3/4 der Befehle ohne die Vererbung noch komplizierter wären

```
public class HalloWelt extends JFrame{

  JLabel schriftZug;

  public HalloWelt(String titel){
     super(titel); // *, ok, super ist vielleicht noch ungewöhlicher als JFrame-Konstruktor-Aufruf
     setDefaultCloseOperation(EXIT_ON_CLOSE); // *, 2x, auch für die Konstante
     setSize(300, 300); // *
     Container cp = getContentPane(); // *
     cp.setLayout(new BorderLayout());
     
     schriftZug = new JLabel("HalloWelt");  
     cp.add(schriftZug,BorderLayout.NORTH); // *

     setVisible(true); // *

  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
```


----------



## DerAlk (24. Okt 2011)

SlaterB hat gesagt.:


> das letzte Programm auf der Seite zeigt, wie 3/4 der Befehle ohne die Vererbung noch komplizierter wären



Also meinst Du, dass es hier sinnvoll von JFrame zu erben, da die Befehle sonst komplizierter wären oder hast Du dich unglücklich ausgedrück und/oder ich dich missverstanden?


----------



## SlaterB (24. Okt 2011)

meine Meinung stand im Posting von 15:37: nicht notwendig, "aber in GUIs ist das schon ziemlich handlich und übersichtlich",
wenn ich mich zu "sinnvoll" ja oder nein entscheiden muss: ja


----------



## André Uhres (25. Okt 2011)

Vererbung sollte wohl tiefere Gründe haben, als nur eine Referenz zu sparen .

Gruß,
André


----------



## SlaterB (25. Okt 2011)

und wenn man die paintComponent eines JPanels überschreibt, dann ist es ok?
dann nutzt man gleich eine eigene Klasse auch für Aufrufe wie setBackground(), setPreferredSize() usw?
das ist doch auch nicht konsequent, dort könnte man doch genauso ein JPanel-Attribut verwenden:

```
class CompPanel {
   JPanel p; 
  
    p.add(..);
    p.add(..);
}

class PaintPanel {
   JPanel p = new JPanel() {
           paintCompoent() {
                ...
           }
    }; 
  
    p.set(..);
}
```
dagegen finde ich Erben in beiden Fällen ehrlicher und einheitlicher


----------



## André Uhres (25. Okt 2011)

SlaterB hat gesagt.:


> und wenn man die paintComponent eines JPanels überschreibt, dann ist es ok?



Dann liegt ja auch ein triftiger Grund vor.

Wenn man das Verhalten einer bestehenden Klasse ändern will, kommt man oft um eine Erweiterung durch Vererbung nicht herum. Letztlich wird ja in Deinem Beispiel ebenfalls ein JPanel durch eine anonyme Klasse erweitert .

Gruß,
André


----------



## bygones (25. Okt 2011)

stimme Andre zu. Vererbung aufgrund von Faulheit zu nehmen ist unsinnig und kontraproduktiv. Nur weil man setSize statt frame.setSize schreiben will Vererbung zu nehmen ist falsch.


----------



## SlaterB (25. Okt 2011)

klar, um Vererbung kommt man nicht drumherum, ich frage mich dabei, ob ihr das dann auch wie im Beispiel PaintPanel wieder per Attribut lösen würdet?
denn das Überschreiben bedeutet ja nicht, dass sonstiger Initialisierungs-Code auch in die neue JPanel-Subklasse gehört,
wenn aber doch dann ist die Einheitlichkeit schon ein einigermaßen bedeutender Grund, z.B. in der Außensicht wie vorher angesprochen:

auf höherer Ebene steht

```
add(getPaintPanel()); // geht direkt weil PaintPanel von JPanel erbt für paintComponent
add(getCompPanel().getPanel()); // geht nicht direkt weil Vererbung vermieden wurde
```
? das wäre doch schrecklich

als Alternativen bleibt nur
- PaintPanel und CompPanel erben beide nicht von JPanel, umständliche Konstruktion für paintComponent, siehe vorheriges Posting
- oder beide erben von JPanel, ganz normaler Standard, eine Klasse die Panel heißt darf auch ruhig ein JPanel sein (!)

wie ist die Wahl, Mischen, nie die eigenen Klassen erben lassen (sondern höchstens JPanel-Attribut) oder immer erben?

schade dass es nicht wirklich große Beispiel-GUIs mit extra Klassen für Unterpanel gibt, oder kennt jemand welche, vielleicht eigene? 
Using Layout Managers (The Java™ Tutorials > Creating a GUI With JFC/Swing > Laying Out Components Within a Container)
benutzt Vererbung, gilt aber vielleicht nicht als positives Beispiel


----

bei welchen anderen Klassen steht diese Entscheidung noch an?
bei Collections lohnt allein schon nicht wegen theoretischer Wahl unterschiedlicher Implementierungen,
Thread ist bekannt,

Applet macht es eher leicht weil Methoden zu implementieren sind, strenggenommen gilt aber dasselbe wie bei JPanel,
der Umstand wird auch gerne für alles andere genutzt, inkonsequent,
hier ein Beispiel dann auch mal wieder mit erbenden JPanel,
Learning Java - Chapter 7 : Java

von Socket/ ServerSocket würde niemand erben, da sind die Vorlagen/ der Gebrauch sicher richtiger,
viel mehr fällt mir kaum ein


----------



## Marco13 (25. Okt 2011)

Dieses "Vererben um Aufrufe/Dereferenzierungen zu sparen" findet seine IMHO absurdesten Auswüchse in sowas wie Double Brace Initialization :autsch:


----------



## Camino (25. Okt 2011)

bygones hat gesagt.:


> stimme Andre zu. Vererbung aufgrund von Faulheit zu nehmen ist unsinnig und kontraproduktiv. Nur weil man setSize statt frame.setSize schreiben will Vererbung zu nehmen ist falsch.


Hmm, also ich hatte das zu Anfang so gelernt bzw. beigebracht bekommen. Und bei mir hat das eigentlich auch nichts mit Faulheit zu tun, sondern ich finde es eigentlich übersichtlicher, wenn mein Hauptframe in einer eigenen Klasse steht und diese Klasse dann auch ein JFrame sein kann (weil es ja auch einer ist). Warum nicht. Dachte ich jedenfalls bisher immer. In meinem Hauptframe passiert ja eigentlich auch nicht so richtig viel: Titel, Grösse, Position auf dem Bildschirm, Menü, Toolbar, Statusleiste und dann das MainPanel in den CENTER-Bereich. Ich brauche also auch nicht die Möglichkeit, evtl. noch von einer anderen Klasse erben zu müssen.

Bisher hatte ich eine Startklasse (mit der main-Methode drin), in welcher ein Objekt des Hauptframes erzeugt wurde (einfach nur mit new HauptFrame() ). Ihr meint also, es wäre besser, wenn ich dort in dieser Klasse das JFrame-Objekt erzeugen, konfigurieren und mit den Komponenten füllen würde? So richtig überzeugt bin ich immer noch nicht. Ich sehe immer noch keine richtigen Nachteile, und Vorteile, ausser jetzt wegen der Übersichtlichkeit.


----------



## bygones (25. Okt 2011)

wir hatten hier schonmal die Diskussion und da kam raus, dass das Hauptproblem bei Swing leider ist, dass keine korrekte Schnitstellen zur Verfuegung stehen.

Ich sag auch nicht, dass man jegliche componente immer per Komposition nehmen soll.

Vererbung ist jedoch wie der Hammer in der Hand, und alles sieht dann aus wie ein Nagel. 

das Problem mit der Vererbung vor allem ist eben das veroeffentlichen aller Methoden der Oberklasse. hat man einen Panel der ganz toll was bestimmtes macht, ein bestimmtes layout verwendet, somit die komponents toll anordnet etc. Nutzt man nun Vererbung geht die eigentliche addComp Methode unter all den anderen adds unter und jeder Verwender kann ganz leicht die Anordung bzw den gedachten Sinn der Component aushebeln bzw falsch gebrauchen. Bei der Komposition hat man nicht das Problem, da man dort nur die methoden so anbieten, wie ein Verwender sie nutzen soll.

Das jedoch ist in der Swing welt aufgrund der fehlenden Schnittstellen nicht so einfach zu realisieren.

Ich persoenlich wuerde es immer so machen dass ich mit Komposition anfange und nur wenn es definitiv nicht weiter geht Vererbung als Moeglichkeit in Betracht ziehen


----------



## DerAlk (28. Okt 2011)

Abschließend hierzu noch einmal vielen Dank.
Meine Frage wurde dahingehend beantwortet, bzw. sehe ich sie als beantwortet an, dass das Erben von JFrame eigentlich nicht richtig ist, so lange man nicht die Funktionalität des Fensters verändern muss.
Trotzdem sieht man es immer wieder in Code-Beispielen und so wie einige berichtet haben, scheint es ja auch durchaus gelehrt worden zu sein/wird es noch.


----------



## DrZoidberg (30. Okt 2011)

Also wenn es nur darum geht den Code etwas kürzer oder übersichtlicher zu gestalten kann man auch den anonymen Konstruktor verwenden.


```
JFrame frame = new JFrame("Hallo Welt") {{
    setSize(300,300);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
}};
```


----------



## Gast2 (30. Okt 2011)

Was du hier erstellst ist ne anonyme Klasse, kein anonymer Konstruktor.
Das ganze nennt sich dann double brace initialization.


----------



## DrZoidberg (30. Okt 2011)

EikeB hat gesagt.:


> Was du hier erstellst ist ne anonyme Klasse, kein anonymer Konstruktor.
> Das ganze nennt sich dann double brace initialization.



Bei der "double brace initialization" handelt es sich um eine anonyme Klasse mit einem anonymen Konstruktor.


```
class Klasse {

Klasse() {
//normaler Konstruktor
}

static {
//statischer Konstruktor
}

{
//anonymer Konstruktor
}
}
```


----------



## hdi (30. Okt 2011)

Afaik lautet die richtige Terminologie:


```
class Klasse {
 
Klasse() {
//normaler Konstruktor
}
 
static {
//statischer Initialisierungsblock
}
 
{
//nicht-statischer Initialisierungsblock
}
}
```

Erstmal gibt's im statischen Kontext sowas wie einen Konstruktor gar nicht. Ein Konstruktor erzeugt ein Objekt. Und der nicht-statische Init-Block ist auch kein Konstruktor, denn ein Konstruktor wird nach wie vor aufgerufen. Der Init-Block wird im Zuge der Instanz-Initialisierung ausgeführt, vor dem Konstruktor. Mach doch mal ein Sysout in deinen "normalen Konstruktor" oben, und eines da rein was du als "anonymen" Konstruktor bezeichnest. Und dann erzeug mal eine Instanz.


----------

