Hallo. Mir ist in einem Uralt-tutorium zu AWT aufgefallen, dass man bei Java mehrere Top-Level Klassen benutzen kann. Wie ist das möglich? Wenn ich das versuche, gibt mir Eclipse die Fehlermeldung “public type soundso must be defined in its own file”. Hier der relevante code:
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
/** The application class. Processes high-level commands sent by GUI */
public class Draw {
/** main entry point. Just create an instance of this application class */
public static void main(String[] args) { new Draw(); }
/** Application constructor: create an instance of our GUI class */
public Draw() { window = new DrawGUI(this); }
protected Frame window;
/** This is the application method that processes commands sent by the GUI */
public void doCommand(String command) {
if (command.equals("clear")) { // clear the GUI window
// It would be more modular to include this functionality in the GUI
// class itself. But for demonstration purposes, we do it here.
Graphics g = window.getGraphics();
g.setColor(window.getBackground());
g.fillRect(0, 0, window.getSize().width, window.getSize().height);
}
else if (command.equals("quit")) { // quit the application
window.dispose(); // close the GUI
System.exit(0); // and exit.
}
}
}
/** This class implements the GUI for our application */
class DrawGUI extends Frame {
Draw app; // A reference to the application, to send commands to.
Color color;
...```
In einer Datei darf nur eine “öffentliche” Klasse sein, jedoch zusätzlich noch weitere “package private” Klassen.
//...
}
class Fribbel {
//...
}```funktioniert
```public class Jabbel {
//...
}
public class Fribbel {
//...
}```funktioniert nicht. Selbiges gilt für "protected" und "private", aber das funktioniert bei Top-Level-Klassen ohnehin nicht.
Man sollte noch dazu sagen, dass sowas zwar geht, die Verwendung dieses Features aber völlig unüblich ist. Ich könnte mir auch vorstellen, dass das einige Tools aus dem Tritt bringen könnte.
Nein, ich meinte mehrere Top-Level-Klassen in einer Datei sind unüblich. Innere Klassen sieht man recht oft, und sie sind auch nützlich (nur **lokale **innere Klassen - also nicht-anonyme Klassen innerhalb von Methoden - scheinen ein gescheitertes Experiment zu sein).
Also es gibt
tlc in einer/derselben Datei (für die Übersicht nicht so toll, 2x public, verboten),
statische innere Klassen (nützlich),
innere Klassen (an die Instanz gebunden) und
anonyme innere Klassen (praktisch für alles Mögliche, z. B. Interface implementieren).
Mehr gibt’s imho nicht.
Wann wird das Wort “lokal” verwendet, wenns nicht ums Rädern geht?
Man sollte noch dazu sagen, dass Compilerchen auch aus einer Datei mehrere Bytecode-Dateien machen kann und auch macht.
Du solltest sich daran orientieren, was in deiner Firma Usus ist und ,wie deine Arbeitskollegen das finden und was in guterer Literatur zu diesem Thema steht.
[QUOTE=CBBB]Also es gibt
tlc in einer/derselben Datei (für die Übersicht nicht so toll, 2x public, verboten),
statische innere Klassen (nützlich),
innere Klassen (an die Instanz gebunden) und
anonyme innere Klassen (praktisch für alles Mögliche, z. B. Interface implementieren).
Mehr gibt’s imho nicht.
Wann wird das Wort “lokal” verwendet, wenns nicht ums Rädern geht?[/QUOTE]Lokale innere Klassen (nur durch innerhalb der Klasse instanzierbar) eignen sich dazu Interfaces zu implementieren, die zurückgegeben werden müssen (siehe z.B. Implamentationen von Collections und Maps). Bei anonymen und Instanz gebundenen inneren Klassen fängt man sich recht schnell eine verdeckte Instanz ein. Wenn man mit so etwas z.B. ein Interface oder einen Listener implementiert und diesen irgend wohin heraus gibt, muss man sich nicht wundern, wenn ein Objekt mal nicht abgeräumt wird, obwohl es eigentlich gar nicht mehr erreicht werden kann. Sowas fällt einem aber erst auf, wenn man mit der “java.lang.ref”-API arbeitet/rum experimentiert.
Und ja… mehrere TLCs in einer Datei sind nicht nur unüblich, sondern auch verwirrend. Z.B. dann, wenn man eine Klasse erstellen möchte, die in diesem Paket schon existiert. Wenn man nun wissen will, wo diese Klasse definiert wurde, sucht man sich evtl. 'nen Wolf (ohne IDE zumindest).
Anscheinend gibt es bei einigen (wie CBBB) Unklarheiten darüber, was mit “lokalen inneren Klassen” gemeint ist - nicht besonders verwunderlich, weil sie in freier Wildbahn kaum anzutreffen sind. Im Prinzip handelt es sich um eine normale Klassendefinition, allerdings innerhalb einer Methode. Hier ein Beispiel: http://openbook.galileocomputing.de/javainsel9/javainsel_08_001.htm#mj2518319e7d43802c20b7287386561781
Ahhhh… ja. Da hätt’s mich auch als Beispiel nehmen können, denn diese Art der Klassendefinition kabbte ich noch gar nicht bzw. sie ist mir noch nicht über den Weg gelaufen. Dachte als immer lokale Klassen bezeichnet man solche, die private als modifier haben. Aber mal ‘ne andere Frage… wozu braucht man lokale Klassen? Macht doch eigentlich nur Sinn, wenn man innerhalb einer Methode eine anonyme Klasse benötigt, die eine andere erweitert oder seh’ ich das falsch?
Wie gesagt, habe ich dafür bisher kaum Anwendungsfälle gesehen, von mir aus könnten sie ruhig wegfallen. Du kannst innerhalb einer Methode ganze Klassenhierarchien aufbauen wenn du willst - vielleicht ist das ja bei automatischer Codegenerierung oder so interessant, aber ein handfestes Beispiel für einen Anwendungsfall kann ich dir auch nicht bieten. Ich hätte stattdessen viel lieber Methoden in Methoden (die dann auch Variablen der äußeren Methode sehen könnten), das wäre bedeutend nützlicher.
[quote=Landei]Ich hätte stattdessen viel lieber Methoden in Methoden[/quote]Wie sollte den sowas aussehen?
Ich denke, dass sich diese Problematik auflösen würde, wenn man nicht versucht Objekte möglichst zu vermeiden…
//Fantasie-Code: lokale Methoden wie in Scala
public long fib(int n) {
long fib(long a, long b, int index) {
return index == n ? a : fib(b, a+b, index+1);
}
return fib(0L,1L,0);
}
So wie es da steht sehe ich keinen Vorteil gegenüber einer “klassischen” Implementierung, außer dass ein Parameter gespart wurde. Dafür leidet die Lesbarkeit enorm.
Mach mal ein “richtiges” Beispiel, dass mit Java8 nicht nachstellbar wäre…
[QUOTE=Landei]```
//Fantasie-Code: lokale Methoden wie in Scala
public long fib(int n) {
long fib(long a, long b, int index) {
return index == n ? a : fib(b, a+b, index+1);
}
return fib(0L,1L,0);
}
[QUOTE=Landei;91445]```
public long fib(int n) {
class FibUtil(){
long fib(long a, long b, int index) {
return index == n ? a : fib(b, a+b, index+1);
}
}
return new FibUtil().fib(0L,1L,0);
}
```[/QUOTE]Ist zwar nochmehr overhead, aber es geht :twisted:
[quote=Natac]ür genau sowas kannst du doch lokale Klassen nutzne!?[/quote]noch 2 Zeilen mehr wo er doch nur 'nen Parameter einsparen wollte?
Und dann muss n ja auch noch final sein…
[QUOTE=Natac]Mal abgesehen davon, das es nicht üblich und damit auch nicht sofort leserlich ist: Für genau sowas kannst du doch lokale Klassen nutzne!?
Ist zwar nochmehr overhead, aber es geht :twisted:[/QUOTE]
Mittlerweile kann man ja auch auf Lambdas zurückgreifen - allerdings ist die Implementierung der Rekursion dann ein (allerdings lösbares) Problem.
und um eine Gelegenheit zum Besser-Meckern nicht auszulassen:
in diesem Beispiel wird ja gar kein Parameter richtig gespart/ von der ‚äußeren Methode‘ benötigt
{
return index == 0 ? a : fib(b, a + b, index - 1);
}
public static long fib(int n)
{
return fib(0L, 1L, n);
}
Ja. Aber hier wird eben auch deutlich, dass die private Version besser nicht in der Klasse, sondern nur innerhalb der public-Methode sichtbar sein sollte, allein schon weil die API eben “Vorwissen” benötigt (nämlich wie a und b vorbelegt werden muss), was eine Fehlbenutzung wahrscheinlich werden lässt. In diesem “Spielbeispiel” mag das noch nicht überzeugen, aber wenn man sich z.B. den Code von BigInteger anschaut, in dem es von Hilfsmethoden (wie lucasLehmerSequence, passesLucasLehmer, passesMillerRabin) nur so wimmelt, wird schnell klar, dass hier eine Methoden-Schachtelung enorm helfen würde.