static - Methoden

J

javaguest456

Gast
Java:
class HelloWorld {
public static void(String[] args) {
  System.out.println("Hello world"); 
} 
}

Ich bin mir nicht ganz sicher, weshalb die main()-Methode als static deklariert werden muss.

Hier, wie ich es verstehe:

In den Lehrbüchern heißt es: Das Schlüsselwort static ist dazu da, um Methoden aufzurufen, die nicht ans Instanzen einer Klasse gebunden sind.

Java:
class Auto {
  void tuwas() {
  }
} 

Auto x = new Auto(); 
x.tuwas(); 
// Die Methode tuwas() ist gebunden an 'x', eine Instanz der Klasse 'Auto'

Und main() ist eben nicht an eine Instanz der Klasse HelloWorld (obiges Beispiel) gebunden - darum muss sie static sein. Richtig?!

Was ich mich jetzt aber fragen: Wann ist es noch sinnvoll oder sogar unumgänglich, eine Methode als static zu zu deklarieren? Kann mir jemand ein Beispiel geben? Danke!
 

Mujahiddin

Top Contributor
static ist eine Klassenmethode, das hast du richtig verstanden.
die main-Methode ist die Eingangsstelle eines Javaprogramms, also muss diese als static deklariert werden - ansonsten müsste ein Objekt der Klasse (z.B. Main) erzeugt werden, um dann "main" aufzurufen.
Vielleicht wird es bei Instanz/Klassenvariablen deutlicher:

Java:
public class Auto {
    private static int anzahlAllerErstelltenAutos = 0; // Betrifft keine Instanz, sondern ist ein einziges Mal für die Klasse Auto vorhanden
    public final int autoID;

    public Auto() {
        autoID = anzahlAllerErstelltenAutos++;
    }
    
    public int welcheIDHatDiesesAuto() { // oder "dasWievielteAutoIstDiesesHier()", da in diesem Fall ID = Nummer der Stelle ist.
        return autoID;
    }
    
    public static int wieVieleAutosGibtEs() {
        return anzahlAllerErstelltenAutos;
    }
}

Verstehst du das Konzept?
 

Marco13

Top Contributor
Was ich mich jetzt aber fragen: Wann ist es noch sinnvoll oder sogar unumgänglich, eine Methode als static zu zu deklarieren?

Unumgänglich ist es selten. Man kann jede static-Methode in eine nicht-static verwandeln, indem man das "static" wegnimmt (und dann - falls möglich - eine Instanz erzeugt und die (dann nicht-statische) Methode darauf aufruft).

Sinnvoll ist es oft. Ich propagiere ja, dass man Methoden IMMER static machen sollte, wenn man sie ohne Verrenkungen static machen kann - also insbesondere wenn sie nicht den internen Zustand des Objektes verändern, auf dem sie aufgerufen werden. Man kann das dann meinetwegen "Utility-Methoden" nennen, und die in einer eigenen Klasse zusammenfassen. (Die Klasse "Math" ist vielleicht ein Beispiel, wenn auch kein sehr gutes für diesen Fall). Das schöne an static-Methoden ist eben, dass sie rein funktional sind. Parameter rein, Ergebnis raus. Es gibt keine ungültigen Zustände oder Vorbedingungen. Insbesondere sind sie damit auch automatisch thread-safe (das gilt aber nur, wenn man nicht auch einen statischen Zustand hat, wie im Beispiel des Gotteskriegers)
 

Andreas29

Bekanntes Mitglied
Hi,

auch wenn das eventuell ein wenig zu weit führt, sei hier doch eins noch zum Thema static angemerkt:
Man kann statische Methoden nicht überschreiben. Dies bedeutet, wenn ich eine Klasse schreibe, die z.B. eine mathematische Berechnung durchführt (meinestwegen irgendeine Zinsberechnung) kann ich sie problemlos statisch machen, solange ich von der Klasse, die diese Methode zur Verfügung stellt, nicht ableiten will. Sobald ich von der Klasse mit der statischen Methode eine Kindklasse baue und in dieser Kindklasse die Berechnung verändern will, habe ich ein Problem, weil dies nicht möglich ist.

Da ich aber oftmals nicht weiß, ob ich zu einer Utility-Klasse irgendwann mal ein Kind brauche, schreibe ich (soweit irgend möglich) keine statischen Methoden, um mir die Möglichkeiten, die mir die Objektorientierung liefert, nicht gleich wieder zu zerstören.

Nur so als Hinweis...

Grüße,
Andreas
 

Mujahiddin

Top Contributor
Hi,

auch wenn das eventuell ein wenig zu weit führt, sei hier doch eins noch zum Thema static angemerkt:
Man kann statische Methoden nicht überschreiben. Dies bedeutet, wenn ich eine Klasse schreibe, die z.B. eine mathematische Berechnung durchführt (meinestwegen irgendeine Zinsberechnung) kann ich sie problemlos statisch machen, solange ich von der Klasse, die diese Methode zur Verfügung stellt, nicht ableiten will. Sobald ich von der Klasse mit der statischen Methode eine Kindklasse baue und in dieser Kindklasse die Berechnung verändern will, habe ich ein Problem, weil dies nicht möglich ist.

Da ich aber oftmals nicht weiß, ob ich zu einer Utility-Klasse irgendwann mal ein Kind brauche, schreibe ich (soweit irgend möglich) keine statischen Methoden, um mir die Möglichkeiten, die mir die Objektorientierung liefert, nicht gleich wieder zu zerstören.

Nur so als Hinweis...

Grüße,
Andreas

Ich kann dir nicht zustimmen...
Die Tatsache, dass man statische Methoden nicht erben kann, ist ja gerade der Sinn daran.
Code:
static
bedeutet für mich nichts anderes als "Klassen-X", entweder Klassenvariable (wie bei autoID) oder Klassenmethode.
Zu deinem Zins-Beispiel:
Angenommen, du hast eine abstrakte Klasse
Code:
Bank
, dann wäre es hier sinnvoll, eine allgemeine Funktion
Code:
static BigDecimal zinsBerechnen(BigDecimal base, double percent){ ... }
zu haben, die du von mir aus auch in eine Utility-Klasse schreibst. In deine Bank-Klasse kommt höchstens eine Methode
Code:
abstract void monatsabrechnung();
und in die Unterklassen die jeweiligen Methoden unter Verwendung von "zinsBerechnen".
 

Marco13

Top Contributor
Man kann statische Methoden nicht überschreiben. ...

Da ich aber oftmals nicht weiß, ob ich zu einer Utility-Klasse irgendwann mal ein Kind brauche, schreibe ich (soweit irgend möglich) keine statischen Methoden, um mir die Möglichkeiten, die mir die Objektorientierung liefert, nicht gleich wieder zu zerstören.

Bei oberflächlicher Betrachtung mag das stimmen. Ich finde, es ist schon eine Designentscheidung, ob man eine Methode statisch oder nicht statisch oder überschreibbar oder nicht überschreibbar macht. Und wie so oft sind Designentscheidungen nicht leicht - deswegen hatte ich auch mal gefragt: http://www.java-forum.org/allgemein...embermethoden-statische-utility-methoden.html . Der letzte Beitrag enthält aber schon einen Hinweis darauf, wie die "Vererbung" von static Methods in Zukunft einfacher wird, bzw. wie Vererbung und Erweiterbarkeit durch static methods in Zukunft sogar unterstützt wird: Durch die "defender methods" in Java 8 wird es bald möglich sein, statische Methoden als default-Implementierungen von Methoden zu verwenden, die in Interfaces definiert sind.
 
N

nillehammer

Gast
Ich habe zum Thema folgende -zugegeben recht exteme- Meinung: Als interne Hilfsmetoden für meinen eigenen Code nutze ich statische Methoden. Mit intern meine ich, dass nur mein eigener Code sie aufruft und aufrufen kann. D.h. sie haben allerhöchstens package-Sichtbarkeit. public static Methoden vermeide ich vollends, weil ich damit zu viele Implementierungs-Details meiner API sichtbar mache und, weil sich static und extends/implements eben (noch) überhaupt nicht verträgt. Ins Extreme getrieben, habe ich in jedem meiner Packages genau eine public class mit einer public static Methode, nämlich die, mit der man sich Implementierungen der von mir definierten Interfaces holen kann, sonst nichts. Auf die Weise muss ich nur die Interfaces public machen. Sogar die Implementierungen sind nur package-Sichtbar.
 

Ark

Top Contributor
Unumgänglich ist es selten. Man kann jede static-Methode in eine nicht-static verwandeln, indem man das "static" wegnimmt (und dann - falls möglich - eine Instanz erzeugt und die (dann nicht-statische) Methode darauf aufruft).
So einfach ist das eben nicht, wie du schon selbst in Klammern hinzufügst. Das Hauptproblem ist tatsächlich, dass du zum Aufruf einer Instanzmethode eine Instanz der Klasse benötigst, ganz egal, ob du sie in der Methode tatsächlich benötigst oder nicht. Folgender Code ist zwar kein gültiges Java, aber verdeutlicht, wie man sich eine Instanzmethode als statische Methode ungefähr vorstellen kann:
Java:
public class Auto {

	private String name;

	// "richtige" Instanzmethode
	public final void setName(String name){
		this.name = name;
	}

	// Nachbau
	public static void setName(final Auto this, String name){
		if(this == null) throw new NullPointerException();
		this.name = name;
	}
}
Grob würde ich also mal sagen: Wenn du eine statische Methode erzeugst, und in der Parameterliste dieser Methode taucht ein Parameter vom Typ der eigenen Klasse auf, dann machst du was falsch. ;) Besser wäre es dann wahrscheinlich, die Methode nicht statisch zu machen und diesen einen Parameter quasi automatisch [c]this[/c] nennen zu lassen.

Was die Verwendung/Publizierung von statischen Methoden angeht, bin ich nillehammers Meinung: statische Methoden sollte es nur und ausschließlich zur Erzeugung von Instanzen der jeweiligen Klasse geben. (Und öffentliche Konstruktoren gehören abgeschafft!) Ansonsten sollte es gar keine statischen Methoden geben.

Warum? Es gibt da einen ganz wichtigen Grund, der mir selbst erst relativ spät klargeworden ist: Multithreading! Klassenvariablen gibt es nur einmal im gesamten System, und da kann es schnell schwierig werden, sobald mehrere Threads darauf zugreifen wollen. Besser wäre es, wenn man sich pro Thread eine Instanz erzeugen könnte, die man dann logischweise nur in diesem einen Thread verwenden kann/sollte. Eine solche Instanz könnte dann z.B. Werte zwischenspeichern, die während bestimmer Berechnungen anfallen, und auf diese Werte wieder zurückgreifen, um folgende Berechnungen zu beschleunigen.

Noch ein konkretes Beispiel: In der Dokumentation zur Methode [c]java.lang.Math.random()[/c] heißt es selbst:
This method is properly synchronized to allow correct use by more than one thread. However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.

Und noch ein Beispiel mit Math: Es gibt nur eine Klasse Math. Aber auch nur eine Klasse StrictMath! Und was ist, wenn ich Implementierungen trigonometrischer Funktionen benötige, die zwar nicht so exakt, aber dafür viel, viel schneller sind? Tja. Dagegen könnte ich mit eigenen Math/StrictMath/MyMath-Instanzen sogar zur Laufzeit auf die Implementierung umschalten, die gerade gut genug ist.

Ark
 
D

dhalsim

Gast
Ein anderer wichtiger Punkt neben der nicht vorhandenen Flexibilität ist die Testbarkeit. Prozeduren (genau das sind statische Methoden im Endeffekt) lassen sich im Gegensatz zu Objekten und ihren Methoden, welche gegen Interfaces (im weiteren Sinn) programmiert wurden, nur sehr schlecht isoliert betrachten, vereinfachen und ersetzen. Sie stehen praktisch wie in Stein gemeißelt im Code.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Folgender Code ist zwar kein gültiges Java, aber verdeutlicht, wie man sich eine Instanzmethode als statische Methode ungefähr vorstellen kann:
...

In Sprachen, die nicht so sehr in ihrer eigenen (VM-) Welt leben, wie Java, IST das sogar so. Ich weiß noch, dass die ersten Debugger von C++-IDEs, die erst aus C-Debuggern heraus entstanden waren, in den Methodensignaturen immer diesen ominösen zusätzlichen Zeiger als ersten Parameter hatten ???:L :idea: ...

Was die Verwendung/Publizierung von statischen Methoden angeht, bin ich nillehammers Meinung: statische Methoden sollte es nur und ausschließlich zur Erzeugung von Instanzen der jeweiligen Klasse geben. (Und öffentliche Konstruktoren gehören abgeschafft!) Ansonsten sollte es gar keine statischen Methoden geben.

Warum? Es gibt da einen ganz wichtigen Grund, der mir selbst erst relativ spät klargeworden ist: Multithreading!

Das Multithreading hatte ich ja explizit als ein Argument FÜR statische Methoden aufgeführt - aber mit dem Hinweis darauf, dass die Methode nichts mit einem statischen Zustand zu tun haben dürfen. Statische Variablen sind GANZ schlecht, bzw. man muss höllisch aufpassen (sofern man nicht Lust hat, überall die dicke synchronized-Keule auszupacken). Statische Methoden (die nicht auf irgendeinem bäh-bäh-statischen Zustand rumpfuschen) sind immer Thread-Safe. Es sind rein funktionale Einheiten (und "funktional" wirklich im Sinne funktionaler Programmierung).

Wie angedeutet (und im oben verlinkten Thread weiter ausgebreitet) kann man sagen, dass das Fehlen von Polymorphie ein Nachteil sein kann, aber ist das Argument IMHO leicht zu entkräften:
Java:
class ArrayList implements List
{
    public void sort()
    {
        // 200 Zeilen Code, der von der List-Implementierung unabhängig ist
    }
}

class Vector implements List
{
    public void sort()
    {
        // 200 Zeilen Code, der von der List-Implementierung unabhängig ist
    }
}
---->
Java:
class ArrayList implements List
{
    public void sort()
    {
        Lists.sort(this); // Ja, übergebe "this" ;) 
    }
}

class Vector implements List
{
    public void sort()
    {
        Lists.sort(this);
    }
}


class Lists
{
    public static void sort(List list) 
    {
        // 200 Zeilen Code, der von der List-Implementierung unabhängig ist
    }
}

Wenn man nun eine spezielle List-Implementierung anbieten will, bei der nicht die Standard-Sortierung verwendet werden soll, könnte man die Methode entsprechend überschreiben, und eben NICHT an die statische Methode delegieren.

(Wirkt so vielleicht etwas konstruiert, in dem anderen Thread war das etwas ausführlicher...)

Ich würde fast so weit gehen, zu sagen, dass man alle Methoden static machen könnte (selbst WENN sie eine Instanz "ihrer" Klasse übergeben bekommen müssen) wenn sie ihre Aufgabe erfüllen können, indem sie NUR auf den public-Methoden der Klasse arbeiten. Das klingt aber sehr pauschal, deswegen würde ich erst nochmal drüber nachdenken, bevor ich es wirklich sage :D :oops:
 
J

javaguest789

Gast
Zunächst erstmal vielen Dank an alle fürs Antworten.

Java:
public class Auto {
    private static int anzahlAllerErstelltenAutos = 0; // Betrifft keine Instanz, sondern ist ein einziges Mal für die Klasse Auto vorhanden
    public final int autoID;
 
    public Auto() {
        autoID = anzahlAllerErstelltenAutos++;
    }
    
    public int welcheIDHatDiesesAuto() { // oder "dasWievielteAutoIstDiesesHier()", da in diesem Fall ID = Nummer der Stelle ist.
        return autoID;
    }
    
    public static int wieVieleAutosGibtEs() {
        return anzahlAllerErstelltenAutos;
    }
}

Danke, dein Beispiel ist sehr verständlich. Die Methode wieVieleAutosGibtEs() ist als static int deklariert, da sie eben eine Variable von diesem Typ zurückgibt. Habe ich das richtig verstanden?
 

Marco13

Top Contributor
Die Methode wieVieleAutosGibtEs() ist als static int deklariert, da sie eben eine Variable von diesem Typ zurückgibt. Habe ich das richtig verstanden?

Du könntest auch dort das "static" weglassen ;) Wie vielleicht (oder auch nicht) in den bisherigen Antworten deutlich wurde, ist ein riesiger Unterschied zwischen statischen Methoden und statischen Variablen. Statische Variablen sollte man vermeiden, außer wenn man schon sehr genau weiß, was man tut. Schon in diesem Beispiel könnten durch die statische Variable "anzahlAllerErstelltenAutos" Fehler auftreten: Wenn zwei Threads gleichzeitig ein Auto erstellen, könnte die Variable 1 sein, obwohl schon 2 Autos erstellt wurden!

Vielleicht müßtest du nochmal genauer sagen, was die Frage ist ... falls es noch eine gibt...
 

Mujahiddin

Top Contributor
Du könntest auch dort das "static" weglassen ;) Wie vielleicht (oder auch nicht) in den bisherigen Antworten deutlich wurde, ist ein riesiger Unterschied zwischen statischen Methoden und statischen Variablen. Statische Variablen sollte man vermeiden, außer wenn man schon sehr genau weiß, was man tut. Schon in diesem Beispiel könnten durch die statische Variable "anzahlAllerErstelltenAutos" Fehler auftreten: Wenn zwei Threads gleichzeitig ein Auto erstellen, könnte die Variable 1 sein, obwohl schon 2 Autos erstellt wurden!

Vielleicht müßtest du nochmal genauer sagen, was die Frage ist ... falls es noch eine gibt...

Ja, threadsicher war das nicht, war ja auch nur ein kleines Beispiel fürs Verständnis zum Unterschied static/nichtstatic
Aber ich muss dir widersprechen: Der einzige Fehler, der auftreten kann, ist lediglich, dass zwei gleichzeitig erstellte Autos die gleiche ID haben, die ID wird jedoch korrekt inkrementiert.
 

Marco13

Top Contributor
Aber ich muss dir widersprechen: Der einzige Fehler, der auftreten kann, ist lediglich, dass zwei gleichzeitig erstellte Autos die gleiche ID haben, die ID wird jedoch korrekt inkrementiert.

Nun, bei Threads und Race conditions würde ich grundsätzlich nicht wetten ;) aber ... soweit ich weiß ist schon ein vermeintlich simples x++ nicht atomar, geschweige denn das verbunden mit einer Zuweisung. So einen counter könnte/sollte man (wie gesagt, wenn man nicht alles syncrhonized machen will) zumindest mit einem AtomicInteger (Java Platform SE 6) implementieren...
 

Ark

Top Contributor
Der einzige Fehler, der auftreten kann, ist lediglich, dass zwei gleichzeitig erstellte Autos die gleiche ID haben, die ID wird jedoch korrekt inkrementiert.
Hm, klingt irgendwie widersprüchlich. Wenn zweimal die gleiche ID vergeben wird (z.B. 0), dann kann doch beide Male auch nur ein um 1 zu niedriger Wert im globalen Zähler landen (im gleichen Beispiel eben 1). Wenn man also die Bedingung aufstellt, dass der globale Zähler immer die Anzahl der erzeugten Instanzen widerspiegeln muss (und diese Anzahl ist ja unabhängig davon, wie viele verschiedene IDs vergeben wurden), dann wurde dieser Zähler nicht richtig inkrementiert: Es gibt 2 Autos mit der ID 1, aber laut Zähler dürfte es nur 1 Auto geben.

In Sprachen, die nicht so sehr in ihrer eigenen (VM-) Welt leben, wie Java, IST das sogar so. Ich weiß noch, dass die ersten Debugger von C++-IDEs, die erst aus C-Debuggern heraus entstanden waren, in den Methodensignaturen immer diesen ominösen zusätzlichen Zeiger als ersten Parameter hatten ???:L :idea: ...
;)

Das Multithreading hatte ich ja explizit als ein Argument FÜR statische Methoden aufgeführt - aber mit dem Hinweis darauf, dass die Methode nichts mit einem statischen Zustand zu tun haben dürfen. Statische Variablen sind GANZ schlecht, bzw. man muss höllisch aufpassen (sofern man nicht Lust hat, überall die dicke synchronized-Keule auszupacken). Statische Methoden (die nicht auf irgendeinem bäh-bäh-statischen Zustand rumpfuschen) sind immer Thread-Safe. Es sind rein funktionale Einheiten (und "funktional" wirklich im Sinne funktionaler Programmierung).
Solche "reinen" funktional-statischen Methoden nutzen aber bei weitem nicht die Möglichkeiten, die man zur Verfügung hätte. So muss eine solche Methode bei jedem Aufruf ihren gesamten Kontext neu aufbauen (sprich: eventuell zur Berechnung notwendige Objekte erzeugen, Dinge überprüfen etc.), auch wenn es praktisch immer der gleiche ist.

Im Gegensatz dazu könnte ich aber auch einmal ein Eine-Methode-Objekt erzeugen, das bei der Instanziierung auf die konkrete Aufgabe zugeschnitten wird (sprich: der Kontext wird nur einmal aufgebaut). Dieses Objekt kann ich dann für die Aufgabe verwenden, ich muss nur noch die Werte beim Aufruf übergeben, die sich ändern (bzw. aus Sicht des Objekts ändern könnten), und wenn ich fertig bin, werfe ich das Objekt einfach weg. Dazu gibt's kostenlos z.B. Thread-Safety oder die Möglichkeit, im Objekt Werte zwischenzuspeichern.

Etwas krass ausgedrückt: Wenn man statische Methoden verwendet, ist man meines Erachtens sogar noch schlechter dran (was den Entwurf betrifft), als wenn man Singletons verwendet.

Ark
 

Marco13

Top Contributor
Solche "reinen" funktional-statischen Methoden nutzen aber bei weitem nicht die Möglichkeiten, die man zur Verfügung hätte. So muss eine solche Methode bei jedem Aufruf ihren gesamten Kontext neu aufbauen (sprich: eventuell zur Berechnung notwendige Objekte erzeugen, Dinge überprüfen etc.), auch wenn es praktisch immer der gleiche ist.

Im Gegensatz dazu könnte ich aber auch einmal ein Eine-Methode-Objekt erzeugen, das bei der Instanziierung auf die konkrete Aufgabe zugeschnitten wird (sprich: der Kontext wird nur einmal aufgebaut). Dieses Objekt kann ich dann für die Aufgabe verwenden, ich muss nur noch die Werte beim Aufruf übergeben, die sich ändern (bzw. aus Sicht des Objekts ändern könnten), und wenn ich fertig bin, werfe ich das Objekt einfach weg. Dazu gibt's kostenlos z.B. Thread-Safety oder die Möglichkeit, im Objekt Werte zwischenzuspeichern.

Etwas krass ausgedrückt: Wenn man statische Methoden verwendet, ist man meines Erachtens sogar noch schlechter dran (was den Entwurf betrifft), als wenn man Singletons verwendet.

Ich finde jetzt, DAS klingt widersprüchlich: Wenn man ein Objekt erstellt, das irgendeinen "Kontext" hat (was auch immer das im Einzelfall ist) könnte es damit leichter zu Race-Conditions kommen - FALLS dieser "Kontext" durch den Aufruf irgendwie verändert wird. Wenn es nur read-only-Datenstrukturen sind, ist das natürlich kein Problem: Wenn man z.B. irgendeine Map EINmal aufbaut, und die ""statische"" Methode dann darin nachsieht, ist das natürlich Threadsicher, und es würde Sinn machen, die Map nur einmal zu erstellen. Aber vermutlich geht das jetzt langsam über zu verschiedenen Abstufungen verschiedener Umsetzungen, die man zwar (mit einigen Spekulationen und "ich-meinte-aber"s ) ausdiskutieren könnte, was aber nicht nötig ist wenn sich jeder einigermaßen über die Auswirkungen bestimmter Designentscheidungen im Klaren ist.

Ich muß es aber wegen deines Vergleiches nochmal betonen: Ein Singleton impliziert immer* einen statischen Zustand - andernfalls bräuchte man es ja nicht, sondern könnte gleich die Methoden statisch machen und sich den Umweg über getInstance sparen. Und ein statischer Zustand ist schlecht, und hat IMHO nichts mit reinen statischen Methoden zu tun. Letztere sehe ich eher als atomare building blocks, aus denen man komplexere Operationen zusammenbauen kann. (Das klingt im ersten Moment vielleicht ziemlich prozedural, aber ist eher so gemeint wie z.B. die Methoden Collections#sort, Collections#max etc...)


* Es gibt auch Singletons ohne Zustand. Ich habe auch schon sowas gesehen wie
Java:
public class Utilities<T>
{
    abstract void doSomething(T t);

    class HundUtilities extends Utilities<Hund> { ... }
    class KatzeUtilities extends Utilities<Katze> { ... }

    public static Utilities<T> getInstance(Object object)
    {
        if (object instanceof Hund) return new ((new Utilities()).HundUtilities();
        if (object instanceof Katze) return new ((new Utilities()).KatzeUtilities();
        throwSomeException();
    }

}
So viel zum Thema Polymorphie: Egal wie tief mal die Latte legt, irgendjemand schafft es immernoch, den Limbo zu machen ;)
 

Mujahiddin

Top Contributor
Hm, klingt irgendwie widersprüchlich. Wenn zweimal die gleiche ID vergeben wird (z.B. 0), dann kann doch beide Male auch nur ein um 1 zu niedriger Wert im globalen Zähler landen (im gleichen Beispiel eben 1). Wenn man also die Bedingung aufstellt, dass der globale Zähler immer die Anzahl der erzeugten Instanzen widerspiegeln muss (und diese Anzahl ist ja unabhängig davon, wie viele verschiedene IDs vergeben wurden), dann wurde dieser Zähler nicht richtig inkrementiert: Es gibt 2 Autos mit der ID 1, aber laut Zähler dürfte es nur 1 Auto geben.

Ich dachte eher folgendes:

Java:
this.autoID = zaehler++;

ist das gleiche wie
Java:
this.autoID = zaehler;
zaehler = zaehler + 1;

Wenn jetzt beide Threads ein Auto erstellen, passiert folgendes [extrem unwahrscheinlich]:
Thread1:
Code:
this.autoID = zaehler;
Thread2:
Code:
this.autoID = zaehler;
Thread2:
Code:
zaehler++;
Thread1:
Code:
zaehler++;

Ich denke, du meinst, dass folgendes passiert:

Thread1:
Code:
zaehler = zaehler ... // hier wird der Thread gestoppt, zaehler wird im Cache gespeichert(??)
Thread2: [code]zaehler = zaehler + 1; // wenn zuvor 3, dann 4
Thread1:
Code:
/* macht weiter */ zaehler = zaehlerFromCache + 1; // ebenfalls 4

Keine Ahnung, ob das möglich ist. Oder hab ich dich falsch verstanden?
 

Ark

Top Contributor
@Mujahiddin: Du musst dir die Operationen kleinschrittiger vorstellen:

[…]
(zaehler ist jetzt 3)
Thread1: push zaehler
Thread2: push zaehler
Thread1: push 1
Thread2: push 1
Thread1: add
Thread2: add
(jetzt liegt bei beiden Threads die Zahl 4 auf dem Stapel)
Thread1: pop zaehler (schreibt seine 4 in zaehler)
(zaehler ist jetzt 4)
Thread2: pop zaehler (schreibt seine 4 in zaehler)
(zaehler ist jetzt immer noch 4)
[…]

Das [c]zaehler = zaehler + 1[/c] wird nicht atomar ausgeführt. Das grundsätzliche Problem ist dabei immer: Wie kann ich einen Wert lesen und sofort danach (ohne dass jemand dazwischenfunkt) schreiben?

Ark
 
Zuletzt bearbeitet:

Bernd Hohmann

Top Contributor
auch wenn das eventuell ein wenig zu weit führt, sei hier doch eins noch zum Thema static angemerkt: Man kann statische Methoden nicht überschreiben.

Warum sollte man sie nicht überschreiben können?

Java:
class Test2 {
	public static void main(String args[]) throws Throwable {
		System.out.println("main von test2");
		utility();
	}

	public static void utility() {
		System.out.println("utility von test2");
	}
}

Java:
public class Test3 extends Test2 {
	public static void main(String[] args) {
		System.out.println("main von test3");
		utility();
	}

	public static void utility() {
		System.out.println("utility von test3");
	}
}

Du kannst "utility()" in Test3 auskommentieren und dann wird die Methode von Test2 ausgeführt.

Bernd
 

Mujahiddin

Top Contributor
@Mujahiddin: Du musst dir die Operationen kleinschrittiger vorstellen:

[…]
(zaehler ist jetzt 3)
Thread1: push zaehler
Thread2: push zaehler
Thread1: push 1
Thread2: push 1
Thread1: add
Thread2: add
(jetzt liegt bei beiden Threads die Zahl 4 auf dem Stapel)
Thread1: pop zaehler (schreibt seine 4 in zaehler)
(zaehler ist jetzt 4)
Thread2: pop zaehler (schreibt seine 4 in zaehler)
(zaehler ist jetzt immer noch 4)
[…]

Das [c]zaehler = zaehler + 1[/c] wird nicht atomar ausgeführt. Das grundsätzliche Problem ist dabei immer: Wie kann ich einen Wert lesen und sofort danach (ohne dass jemand dazwischenfunkt) schreiben?

Ark

Ist jetzt schon über einen Monat her, aber ich verstehe nicht ganz!

(zaehler ist jetzt 3)
Thread1: push zaehler > im CPU steht 3
Thread2: push zaehler > im CPU steht 3
Thread1: push 1 > im CPU (anderer Ort?) steht 1
Thread2: push 1 > im CPU (erster Ort?) steht 1
Thread1: add > im CPU steht 2 (1+1) und wird in einem Ort gespeichert
Thread2: add > im CPU steht 3 (2+1)

push holt ja die
Code:
zaehler
-Variable in den CPU-Register (bei falscher Terminologie bitte korrigieren) - ein CPU hat sicherlich mehrere Registerplätze. Bei deiner Argumentation liefe es jawie folgt:

(zaehler ist jetzt 3)
Thread1: push zaehler
Thread2: push zaehler
Thread1: push 1
Thread2: push 1
Thread1: add > 3+1 = 4, steht jetzt dort, wo erst die 3 stand(?)
Thread2: add > 4+1 = 5, das heißt, es lief alles doch nach Plan...


Ich glaube, ich verstehe etwas grundsätzlich falsch...
 

Ark

Top Contributor
push holt ja die
Code:
zaehler
-Variable in den CPU-Register (bei falscher Terminologie bitte korrigieren)
push macht eher das Gegenteil davon: einen Wert (aus einem Register) auf den Stapel schieben ("retten"). Die Argumentation über Register ist übrigens viel zu kompliziert. (Das fällt dir wahrscheinlich nicht auf, weil dir dazu wohl die Grundlagen fehlen.)

Als Einstieg in die Grundlagen sei dieser Ausschnitt aus einem Wikipediaartikel genannt: Umgekehrte Polnische Notation ? Wikipedia Noch mehr Grundlagen gibt's beim Programmieren mit Assembler sowie beim Compilerbau.

ein CPU hat sicherlich mehrere Registerplätze.
Das stimmt typischerweise. Allerdings hilft das in der Argumentation nicht, weil jeder Thread "seine" Register hat. (Das stimmt so natürlich nicht wirklich. Tatsächlich werden die Registerinhalte immer wieder komplett ausgetauscht: Kontextwechsel ? Wikipedia)

Ich glaube, ich verstehe etwas grundsätzlich falsch...
Jeder Thread hat seinen eigenen Stack. (Dies ist ein wesentlicher Unterschied zum Heap, den sich alle Threads teilen.) Beide Threads führen ein und dasselbe Programm aus, das in einem Teil so aussieht (vereinfacht):
Code:
push zaehler
push 1
add
pop zaehler
Die Variable zaehler liegt auf dem Heap (weil zaehler eine Variable eines Klassenobjektes ist, und Objekte liegen auf dem Heap). Mit "push zaehler" wird der Wert von zaehler auf den Stack des Threads kopiert, der gerade ausgeführt wird. "push 1" kopiert den Wert von 1 auf den jeweiligen Stack. Die Addition "add" ersetzt die beiden obersten Stackelemente (die Kopie von zaehler sowie die Kopie von 1) durch die Summe ebendieser Elemente. Und "pop zaehler" kopiert das oberste Stackelement (in dem Fall das Ergebnis der Addition) in die Variable zaehler. (Darüber hinaus entfernt das pop auch das oberste Stackelement, aber das ist gerade egal.)

Hoffentlich ist es jetzt etwas klarer geworden.

BTW: Derart puristisch "nur auf dem Stack" rechnet vielleicht der Java-Interpreter (wobei auch der kurzfristig Register benutzen wird). Erst der JIT-Compiler ersetzt diese Stackoperationen durch Operationen mit Registern. (Beim Kompilieren in Bytecode sind die Register des tatsächlich ausführenden Prozessors noch nicht bekannt, deshalb stehen in der class-Datei nur Stackoperationen.)

Ark
 

Mujahiddin

Top Contributor
Alles klar, vielen Dank! Hab's jetzt einigermaßen verstanden.
Also du versuchst, mit Stacks anstelle von Registern im CPU zu argumentieren, hab ich Recht? Ich war im Trugschluss, dass sich die Thread diesen auch teilen!
 

schalentier

Gesperrter Benutzer
@Bernd Hohmann:

folgendes ist das Problem:

Java:
public class Test {
    public static class Super {
        public static String getStatic(){
            return "SuperStatic  ";
        }
        public String getInstance() {
            return "SuperInstance";
        }
        public static String getStaticWithCall() {
            return getStatic();
        }
        public String getInstanceWithCall() {
            return getInstance();
        }
    }

    public static class Sub extends Super {
        public static String getStatic() {
            return "SubStatic    ";
        }

        @Override
        public String getInstance() {
            return "SubInstance  ";
        }
    }

    public static void main(String[] args) {
        Super superInstance = new Super();
        Sub   subInstance   = new Sub();
        System.out.println("superInstance: " + superInstance.getInstance() + " / " + superInstance.getInstanceWithCall() );
        System.out.println("subInstance:   " + subInstance.getInstance()   + " / " + subInstance.getInstanceWithCall()  );
        System.out.println("Super:         " + Super.getStatic()           + " / " + Super.getStaticWithCall() );
        System.out.println("Sub:           " + Sub.getStatic()             + " / " + Sub.getStaticWithCall() );
    }
}

Und die Ausgabe ist:

Code:
superInstance: SuperInstance / SuperInstance
subInstance:   SubInstance   / SubInstance  
Super:         SuperStatic   / SuperStatic  
Sub:           SubStatic     / SuperStatic

Das Problem ist, dass es kein [c]this[/c] gibt auf Klassenebene. Dieses muesste naemlich der Methode [c]getStaticWithCall()[/c] mitgegeben werden.

Im Beispiel beim Aufruf in Zeile 34 waere dieses [c]this[/c] die Klasse [c]Sub[/c]. Dann ginge der Aufruf in Zeile 10 an die richtige Methode.

Aber so ist das in Java leider nicht. Besonders aergerlich ist sowas beim Schreiben von Tests fuer ne Klasse voll mit static Methoden, da man keine dieser Methoden sinnvoll mocken kann. Deshalb am besten die Finger lassen von static. ;-)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S Methoden 2 non-static Methoden, trotzdem Fehler "non static method can not be referenced from a static context" Java Basics - Anfänger-Themen 9
R Schulaufgabe, Bruache Hilfe mit non-static Methoden Java Basics - Anfänger-Themen 2
D Methoden Scannervariablen in static Methoden Java Basics - Anfänger-Themen 5
K Methoden Methoden in Methoden -> static oder nicht? Java Basics - Anfänger-Themen 7
R Schlüsselworte static Methoden und Imports Java Basics - Anfänger-Themen 10
F LogDatei static Methoden Java Basics - Anfänger-Themen 8
capgeti Datentypen Static methoden aus Superklasse mit Generics definieren? Java Basics - Anfänger-Themen 9
K non-static Methoden ausführen? Java Basics - Anfänger-Themen 3
M Datentypen static methoden Java Basics - Anfänger-Themen 5
L Zusammenhang Methoden, Klassen, Objekte, static - sun doku Java Basics - Anfänger-Themen 4
D static Methoden/Variablen Java Basics - Anfänger-Themen 11
O Welcher Object-Lock-Pool bei static Variablen? Java Basics - Anfänger-Themen 3
A Instance methods should not write to "static" fields Java Basics - Anfänger-Themen 4
berserkerdq2 Habe eine Klasse, welche public ist, diese hat eine public Methode, die nicht static ist. Wenn ich nun versuche aufzurufen Probleme? Java Basics - Anfänger-Themen 8
viktor1 Methoden Methode schreiben static void readText (String filename) {...} zu WordHistogramSample.java Java Basics - Anfänger-Themen 13
M static ArrayList in non-static Java Basics - Anfänger-Themen 12
B Static vs non static und Probleme daraus Java Basics - Anfänger-Themen 13
R UML-Bild (Erkennung ob static o. nicht) Java Basics - Anfänger-Themen 18
B Static Attribute in einer Klasse, wie geht das? :O Java Basics - Anfänger-Themen 19
NaZuRe Geld(Wert) von der public static void main in die public static void Blackjack Java Basics - Anfänger-Themen 2
H Static Java Basics - Anfänger-Themen 5
K Ausgaben auf der Konsole (static Varible) Java Basics - Anfänger-Themen 9
S public static boolean Java Basics - Anfänger-Themen 4
Vamecruft Compiler-Fehler public static void zu static String ändern Java Basics - Anfänger-Themen 2
L non-static Fehler Java Basics - Anfänger-Themen 16
S Klassenmethode ohne static Java Basics - Anfänger-Themen 2
M (Sehr großes Problem) Listen als static in anderen Klassen verwendet Java Basics - Anfänger-Themen 12
J Fehlermeldung unklar. non-static variable player0 cannot be referenced from a static context Java Basics - Anfänger-Themen 4
P non-static variable cannot be referenced from a static context Java Basics - Anfänger-Themen 6
V the static method should be accessed is a static way Java Basics - Anfänger-Themen 6
NormanPatrickBenner static non-static Java Basics - Anfänger-Themen 82
N Erste Schritte "non-static method" oder "XYZ can not be resolved" Java Basics - Anfänger-Themen 21
B Email versenden, muss Methode static sein? Java Basics - Anfänger-Themen 7
R static in der Methode Java Basics - Anfänger-Themen 2
E Problem mit static Methode Java Basics - Anfänger-Themen 4
H Vererbung Static Scanner Objekt verwenden - von StdIn in einer importierten Klasse lesen Java Basics - Anfänger-Themen 10
M Cannot make a static reference to the non-static method Java Basics - Anfänger-Themen 10
I Abstrakte Klasse - static Attribute deklarieren Java Basics - Anfänger-Themen 14
C Methoden Unterschied zwichen public int, public static int und public static void Java Basics - Anfänger-Themen 2
J Frage zu: public static void main (String[]args) Java Basics - Anfänger-Themen 1
T Datentypen enum static Chaos (blutiger anfänger) Java Basics - Anfänger-Themen 5
D Das leidige Thema static.... Java Basics - Anfänger-Themen 15
Aprendiendo Interpreter-Fehler "non-static variable this cannot be referenced from a static context" Java Basics - Anfänger-Themen 2
T Problem mit static Java Basics - Anfänger-Themen 6
T static String Variable wird nur beim ersten aufruf durch eine Funktion geändert. Java Basics - Anfänger-Themen 16
S Vererbung Zugriff auf Methode funktioniert nicht (static/non-static) Java Basics - Anfänger-Themen 3
snipesss Was kann 'static'? Java Basics - Anfänger-Themen 4
H Variablen error: non-static variable cannot be referenced from a static context Java Basics - Anfänger-Themen 4
M public static int in ActionListener Java Basics - Anfänger-Themen 6
J static verschachtelte Klassen und innere Klassen Java Basics - Anfänger-Themen 1
H Nicht Static Funktion ohne Objekt aufrufen? Java Basics - Anfänger-Themen 6
E Objekte und static Java Basics - Anfänger-Themen 2
D Erklärung static boolean Java Basics - Anfänger-Themen 6
L Was genau macht "public static void" ? Java Basics - Anfänger-Themen 12
U Erste Schritte cannot be referenced from a static context Java Basics - Anfänger-Themen 1
B ja ja schon wieder einer mit einer public static void main(string[] args) Frage... Java Basics - Anfänger-Themen 8
J Java: static bei Vererbung Java Basics - Anfänger-Themen 5
O Zu viel static im Projekt Java Basics - Anfänger-Themen 9
F Static final Klasse Java Basics - Anfänger-Themen 0
N static und Objekt kombiniert?!? Java Basics - Anfänger-Themen 3
O Wann nutzt man static? Java Basics - Anfänger-Themen 19
B Klassen Eigene "non static" Klasse in Main verwenden! Java Basics - Anfänger-Themen 12
D neue public static class variablen in array speichern? Java Basics - Anfänger-Themen 6
A Static variablen --- Anwendungsbereich Java Basics - Anfänger-Themen 11
B Erste Schritte Wie komme ich aus Static raus?!! Java Basics - Anfänger-Themen 4
V Static Methods Java Basics - Anfänger-Themen 5
W Compiler-Fehler "non-static method cannot be referenced"-Problem Java Basics - Anfänger-Themen 6
S OOP Klasse mit static-Eigenschaften - HashMap füllen Java Basics - Anfänger-Themen 6
3 OOP static class in einer Klasse Java Basics - Anfänger-Themen 6
B static individuell "vererben"? Java Basics - Anfänger-Themen 8
B Erkennen, wann static oder nicht? Java Basics - Anfänger-Themen 7
T Static Fehler Java Basics - Anfänger-Themen 1
R public static void Rückgabe Java Basics - Anfänger-Themen 5
P Compiler-Fehler public static void main, Grundloses Problem Java Basics - Anfänger-Themen 4
A Cannot make a static reference to the non-static field Java Basics - Anfänger-Themen 6
W Variablen Automatisch static? Java Basics - Anfänger-Themen 3
O Warum muss ich static? Java Basics - Anfänger-Themen 6
O Static Java Basics - Anfänger-Themen 15
E non-static method und static context Java Basics - Anfänger-Themen 15
B non static interface Methode Java Basics - Anfänger-Themen 16
J KeyListener,MouseListener,MouseMotionListener und static Java Basics - Anfänger-Themen 7
S Static void Methode Java Basics - Anfänger-Themen 12
Q Unterschied zwischen static und keinem Modifier Java Basics - Anfänger-Themen 15
O Main-Methode static modifier umgehen Java Basics - Anfänger-Themen 10
J Variablen non-static variable Java Basics - Anfänger-Themen 2
P Erste Schritte public oder static oder wie? Java Basics - Anfänger-Themen 7
X Erste Schritte Methode ohne Static Java Basics - Anfänger-Themen 4
B Classpath static block - Verwirrung Java Basics - Anfänger-Themen 2
S Methoden Warum ist sleep static? Java Basics - Anfänger-Themen 9
K static, non-static Krise Java Basics - Anfänger-Themen 4
M Methoden "Non-static method xy cannot be referenced from a static context" Java Basics - Anfänger-Themen 20
J Probleme mit static generische Klasse Java Basics - Anfänger-Themen 6
S Aufruf Einer Methode aus einer anderen Klasse - Static Fehler Java Basics - Anfänger-Themen 4
W Methodenaufruf innerhalb einer Klasse - static vs. this Java Basics - Anfänger-Themen 3
K Objekt erstellen - error: non-static variable this cannot be referenced from a static context Java Basics - Anfänger-Themen 17
H non-static method cannot be referenced from a static context Java Basics - Anfänger-Themen 2
Y Gebrauch von static Java Basics - Anfänger-Themen 29
L Cannot make a static reference to the non-static method Java Basics - Anfänger-Themen 6
T getClass() im static Kontext Java Basics - Anfänger-Themen 12
S Frage zu public static Java Basics - Anfänger-Themen 29

Ähnliche Java Themen

Neue Themen


Oben