Warum werden statische Variablen als böse angesehen?


634

Ich bin ein Java-Programmierer, der neu in der Unternehmenswelt ist. Kürzlich habe ich eine Anwendung mit Groovy und Java entwickelt. Während des gesamten Codes, den ich geschrieben habe, wurde eine ganze Reihe von Statiken verwendet. Ich wurde vom leitenden technischen Los gebeten, die Anzahl der verwendeten Statiken zu reduzieren. Ich habe ungefähr gleich gegoogelt und finde, dass viele Programmierer ziemlich dagegen sind, statische Variablen zu verwenden.

Ich finde statische Variablen bequemer zu verwenden. Und ich gehe davon aus, dass sie auch effizient sind (bitte korrigieren Sie mich, wenn ich falsch liege), denn wenn ich 10.000 Aufrufe einer Funktion innerhalb einer Klasse durchführen müsste, würde ich die Methode gerne statisch machen und Class.methodCall()stattdessen eine einfache Methode verwenden den Speicher mit 10.000 Instanzen der Klasse überladen, richtig?

Darüber hinaus reduzieren Statiken die gegenseitigen Abhängigkeiten von den anderen Teilen des Codes. Sie können als perfekte Staatsinhaber auftreten. Hinzu kommt, dass Statik in einigen Sprachen wie Smalltalk und Scala weit verbreitet ist . Warum ist diese Unterdrückung der Statik unter Programmierern (insbesondere in der Welt von Java) weit verbreitet?

PS: Bitte korrigieren Sie mich, wenn meine Annahmen zur Statik falsch sind.


43
Nur um zu sagen, es gibt keine statischen Variablen oder Methoden auf Smalltalk oder Scala, gerade weil statische Methoden und Variablen gegen die OOP-Prinzipien verstoßen.
Maurício Linhares

87
Mindestens eine Aussage, die Sie machen, ist ziemlich merkwürdig: "Statik reduziert die Abhängigkeiten von den anderen Teilen des Codes". Im Allgemeinen verschärfen sie die Abhängigkeiten. Der Code, in dem der Anruf getätigt wird, ist sehr eng an den aufgerufenen Code gebunden. Keine Abstraktion zwischen direkter Abhängigkeit.
Arne Deutsch

11
Gute Frage ... eher ein Programmierer.SE Fragen tho?
WernerCD

26
In Ihrem zweiten Absatz geht es um ein ganz anderes Thema, nämlich statische Methoden .
Paul

8
Die funktionale Programmierung missbilligt auch den globalen Zustand. Wenn Sie jemals (und sollten ) eines Tages in die FP einsteigen, sollten Sie bereit sein, den Begriff des globalen Staates aufzugeben.
New123456

Antworten:


689

Statische Variablen repräsentieren den globalen Zustand. Das ist schwer zu überlegen und schwer zu testen: Wenn ich eine neue Instanz eines Objekts erstelle, kann ich innerhalb von Tests über seinen neuen Status nachdenken. Wenn ich Code verwende, der statische Variablen verwendet, kann er sich in einem beliebigen Zustand befinden - und alles kann ihn ändern.

Ich könnte noch eine ganze Weile weitermachen, aber je größer das Konzept ist, desto einfacher ist es, darüber nachzudenken, je enger der Umfang von etwas ist. Wir können gut über kleine Dinge nachdenken, aber es ist schwierig, über den Zustand eines Millionen-Leitungssystems nachzudenken, wenn es keine Modularität gibt. Dies gilt übrigens für alle möglichen Dinge - nicht nur für statische Variablen.


57
Das scheint in letzter Zeit ein Argument zu sein, ob Code testbar ist oder nicht. Es ist eine ziemlich fehlerhafte Argumentation. Das Argument sollte "gutes Design" sein, und normalerweise ist gutes Design überprüfbar. Aber nicht umgekehrt: "Ich kann es nicht testen, dafür muss es schlechtes Design sein." Versteh mich nicht falsch, ich stimme deinem Beitrag im Allgemeinen zu.
M Platvoet

144
@M Platvoet: Ich würde sagen, dass bei einer Auswahl zwischen zwei ansonsten gleich gültigen Designs das testbare überlegen ist. Testbar zu sein bedeutet sicherlich nicht, gut entworfen zu sein, aber ich bin selten auf nicht testbare gute Designs gestoßen, und ich denke, sie sind so selten, dass ich kein Problem damit habe, Testbarkeit zu einem allgemeinen Indikator für gutes Design zu machen.
Jon Skeet

9
@M Platvoet - Testbarkeit beeinflusst sowohl die Wartbarkeit als auch die Zuverlässigkeit, und ich würde diese Hauptfaktoren für die Qualität des Designs berücksichtigen. Sie sind sicherlich nicht die einzigen Faktoren, aber meiner Meinung nach sind die Kosten eines bestimmten Codes eine Kombination aus Maschinenzyklen, Entwicklerzyklen und Benutzerzyklen. Die Testbarkeit trifft zwei dieser drei.
Justin Morgan

5
@M Platvoet - Testbarkeit wirkt sich auch auf die Wiederverwendbarkeit aus, da eine entkoppelte Klasse im Allgemeinen einfacher wiederzuverwenden ist.
TrueWill

13
M Platvoet - Ich stimme Ihrem ersten Kommentar hier nicht zu. Ich denke, wenn etwas nicht getestet werden kann, dann ist es schlechtes Design; denn wenn ich es nicht testen kann, kann ich nicht wissen, dass es funktioniert. Würden Sie ein Auto kaufen, wenn der Verkäufer Ihnen sagte: "Das Design dieses Modells verhindert, dass es getestet wird, sodass ich nicht weiß, ob es tatsächlich läuft." Die Testbarkeit ist für Software (und auch für Autos) so wichtig, dass ein kompetentes Design die Aufnahme verlangt.
Dawood ibn Kareem

276

Es ist nicht sehr objektorientiert: Ein Grund, warum Statik von manchen Menschen als "böse" angesehen werden könnte, ist, dass sie dem objektorientierten Paradigma widersprechen . Insbesondere verstößt es gegen das Prinzip, dass Daten in Objekten eingekapselt sind (die erweitert werden können, Informationen verbergen usw.). Statik, wie Sie sie beschreiben, besteht im Wesentlichen darin, sie als globale Variable zu verwenden, um Probleme wie den Umfang zu vermeiden. Globale Variablen sind jedoch eines der bestimmenden Merkmale eines prozeduralen oder imperativen Programmierparadigmas und kein Merkmal eines "guten" objektorientierten Codes. Dies bedeutet nicht, dass das prozedurale Paradigma schlecht ist, aber ich habe den Eindruck, dass Ihr Vorgesetzter erwartet, dass Sie "guten objektorientierten Code" schreiben und wirklich schreiben möchten. "

Es gibt viele Gotchyas in Java, wenn Sie anfangen, Statiken zu verwenden, die nicht immer sofort offensichtlich sind. Wenn beispielsweise zwei Kopien Ihres Programms auf derselben VM ausgeführt werden, werden sie dann den Wert der statischen Variablen ändern und sich gegenseitig beeinflussen? Oder was passiert, wenn Sie die Klasse erweitern? Können Sie das statische Element überschreiben? Geht Ihrer VM der Arbeitsspeicher aus, weil Sie über eine unglaubliche Anzahl von statischen Daten verfügen und dieser Arbeitsspeicher nicht für andere benötigte Instanzobjekte zurückgefordert werden kann?

Objektlebensdauer: Darüber hinaus hat die Statik eine Lebensdauer, die der gesamten Laufzeit des Programms entspricht. Dies bedeutet, dass der Speicher all dieser statischen Variablen auch dann nicht gesammelt werden kann, wenn Sie Ihre Klasse verwendet haben. Wenn Sie beispielsweise stattdessen Ihre Variablen nicht statisch gemacht und in Ihrer main () -Funktion eine einzelne Instanz Ihrer Klasse erstellt und Ihre Klasse dann aufgefordert haben, eine bestimmte Funktion 10.000 Mal auszuführen, sobald diese 10.000 Aufrufe ausgeführt wurden Wenn Sie Ihre Verweise auf die einzelne Instanz löschen, können alle Ihre statischen Variablen durch Müll gesammelt und wiederverwendet werden.

Verhindert bestimmte Wiederverwendungen: Außerdem können statische Methoden nicht zum Implementieren einer Schnittstelle verwendet werden, sodass statische Methoden verhindern können, dass bestimmte objektorientierte Features verwendet werden können.

Andere Optionen: Wenn Effizienz Ihr Hauptanliegen ist, gibt es möglicherweise andere bessere Möglichkeiten, um das Geschwindigkeitsproblem zu lösen, als nur den Vorteil zu berücksichtigen, dass der Aufruf normalerweise schneller als die Erstellung ist. Überlegen Sie, ob die transienten oder flüchtigen Modifikatoren irgendwo benötigt werden. Um die Inline-Fähigkeit zu erhalten, kann eine Methode als endgültig statt als statisch markiert werden. Methodenparameter und andere Variablen können als endgültig markiert werden, um bestimmte Compileroptimierungen basierend auf Annahmen darüber zu ermöglichen, was diese Variablen ändern kann. Ein Instanzobjekt kann mehrmals wiederverwendet werden, anstatt jedes Mal eine neue Instanz zu erstellen. Möglicherweise gibt es Compliler-Optimierungsschalter, die für die App im Allgemeinen aktiviert sein sollten. Möglicherweise sollte das Design so eingerichtet werden, dass die 10.000 Läufe Multithreading-fähig sind und Multiprozessor-Kerne nutzen können. Wenn Portabilität nicht ist '

Wenn Sie aus irgendeinem Grund nicht mehrere Kopien eines Objekts möchten, das Singleton-Entwurfsmuster, hat Vorteile gegenüber statischen Objekten, wie z. B. Thread-Sicherheit (vorausgesetzt, Ihr Singleton ist gut codiert), ermöglicht eine verzögerte Initialisierung, stellt sicher, dass das Objekt bei seiner Verwendung ordnungsgemäß initialisiert wurde, Unterklassifizierung, Vorteile beim Testen und Refactoring Ihres Codes, Ganz zu schweigen davon, dass es VIEL einfacher ist, den Code zu entfernen, um doppelte Instanzen zu vermeiden, wenn Sie Ihre Meinung ändern, nur eine Instanz eines Objekts zu wollen, als Ihren gesamten statischen Variablencode für die Verwendung von Instanzvariablen umzugestalten. Ich musste das schon einmal machen, es macht keinen Spaß, und am Ende müssen Sie viel mehr Klassen bearbeiten, was das Risiko erhöht, neue Fehler einzuführen ... viel besser, wenn Sie die Dinge beim ersten Mal "richtig" einrichten. auch wenn es so aussieht, als hätte es seine Nachteile. Für mich, Die Nacharbeit, die erforderlich ist, wenn Sie später entscheiden, dass Sie mehrere Kopien von etwas benötigen, ist wahrscheinlich einer der zwingendsten Gründe, um Statik so selten wie möglich zu verwenden. Und daher würde ich auch Ihrer Aussage nicht zustimmen, dass Statik die gegenseitigen Abhängigkeiten verringert. Ich denke, Sie werden am Ende Code erhalten, der stärker gekoppelt ist, wenn Sie viele Statiken haben, auf die direkt zugegriffen werden kann, anstatt ein Objekt, das "weiß, wie es geht" etwas "an sich.


11
Ich mag Ihre Antwort, ich denke, sie konzentriert sich auf die richtigen Kompromisse, die in Bezug auf die Statik zu berücksichtigen sind, und nicht auf einige der roten Heringe wie Parallelität und Umfang. Und +1 für Singletons, eine bessere Frage könnte wirklich gewesen sein, wann statische Variablen / Methoden gegen Singletons verwendet werden sollten ...
studgeek

2
Auch wenn der Singleton selbst threadsicher sein kann (z. B. mithilfe von synchronizedMethoden), bedeutet dies nicht, dass der aufrufende Code in Bezug auf den Singleton-Status frei von Race-Bedingungen ist.
André Caron

8
Auch die Statik ist nicht gegen das OOP-Paradigma. Viele OOP-Fanatiker werden Ihnen sagen, dass die Klasse ein Objekt ist und die statische Methode eher eine Methode des Klassenobjekts als dessen Instanzen. Dieses Phänomen ist in Java weniger verbreitet. In anderen Sprachen wie Python können Sie Klassen als Variablen verwenden und auf statische Methoden als Methoden dieses Objekts zugreifen.
André Caron

4
Die letzte Zeile des dritten Absatzes sollte alle Ihre nicht statischen Variablen lauten , wenn ich mich nicht irre.
Steve

1
Object Lifetimeist ein sehr wichtiger Punkt, den @jessica erwähnt hat.
Abhidemon

93

Das Böse ist ein subjektiver Begriff.

Sie kontrollieren die Statik nicht in Bezug auf Schöpfung und Zerstörung. Sie leben auf Geheiß des Programms beim Laden und Entladen.

Da sich die Statik in einem Bereich befindet, müssen alle Threads, die sie verwenden möchten, die Zugriffskontrolle durchlaufen, die Sie verwalten müssen. Dies bedeutet, dass Programme stärker gekoppelt sind und diese Änderung schwerer vorstellbar und zu verwalten ist (wie J Skeet sagt). Dies führt zu Problemen bei der Isolierung der Auswirkungen von Änderungen und wirkt sich somit auf die Verwaltung der Tests aus.

Dies sind die beiden Hauptprobleme, die ich mit ihnen habe.


59

Nein. Globale Staaten sind an sich nicht böse. Aber wir müssen Ihren Code sehen, um zu sehen, ob Sie ihn richtig verwendet haben. Es ist durchaus möglich, dass ein Neuling globale Staaten missbraucht; genauso wie er jedes Sprachmerkmal missbrauchen würde.

Globale Staaten sind absolute Notwendigkeit. Wir können globale Staaten nicht vermeiden. Wir können es nicht vermeiden, über globale Staaten nachzudenken. - Wenn wir unsere Anwendungssemantik verstehen wollen.

Menschen, die versuchen, globale Staaten deswegen loszuwerden, haben unweigerlich ein viel komplexeres System - und die globalen Staaten sind immer noch da, geschickt / idiotisch getarnt unter vielen Ebenen von Indirektionen; und wir müssen immer noch über globale Staaten nachdenken, nachdem wir alle Indirektionen ausgepackt haben.

Wie die Spring-Leute, die verschwenderisch globale Staaten in XML deklarieren und irgendwie denken, dass es überlegen ist.

@ Jon Skeet if I create a new instance of an objectJetzt haben Sie zwei Gründe: den Status innerhalb des Objekts und den Status der Umgebung, in der sich das Objekt befindet.


10
"Ich muss über zwei Dinge nachdenken". Nicht, wenn ich meinen Test nur vom Objektstatus abhängig mache. Was einfacher ist, je weniger globaler Zustand ich habe.
DJClayworth

2
Die Abhängigkeitsinjektion hat nichts mit dem globalen Status oder der globalen Sichtbarkeit zu tun - selbst der Container selbst ist nicht global. Im Vergleich zu "normalem" Code ist das einzige zusätzliche Element, für das ein von einem Container verwaltetes Objekt sichtbar ist, der Container selbst. Tatsächlich wird DI sehr häufig verwendet, um das Singleton-Muster zu vermeiden.
Floegipoky

31

Es gibt 2 Hauptprobleme mit statischen Variablen:

  • Thread-Sicherheit - statische Ressourcen sind per Definition nicht thread-sicher
  • Code-Implizität - Sie wissen nicht, wann eine statische Variable instanziiert wird und ob sie vor einer anderen statischen Variablen instanziiert wird oder nicht

Ich denke, Jon Skeet bezog sich auf denselben Kommentar, den Sie gepostet haben.
RG-3

13
Ich verstehe den Thread-Sicherheitspunkt nicht, ich denke, dass nichts threadsicher ist, wenn Sie es nicht so machen. Dies scheint überhaupt nicht mit statischen Dingen zu tun zu haben. Bitte korrigieren Sie mich, wenn mir etwas fehlt.
Zmaster

1
@Zmaster - Zwar ist Thread-Sicherheit kein Problem, das ausschließlich statischen Variablen vorbehalten ist, da sie nach ihrer Definition aus und in unterschiedlichen Kontexten aufgerufen werden sollen, aber für sie eher
beschnitten

2
@sternr Ich verstehe, was du meinst, Ereignis, wenn "verschiedene Kontexte" nicht unbedingt gleich "verschiedene Threads" sind. Es ist jedoch richtig, dass die Thread-Sicherheit bei statischen Ressourcen häufig berücksichtigt werden muss. Sie sollten in Betracht ziehen, den Satz zu klären.
Zmaster

Es gibt beispielsweise gültige thread-sichere Verwendungen statischer Ressourcen. private static final Logger LOG = Logger.getLogger (Foo.class); private static final AtomicInteger x = neue AtomicInteger (0); Soweit ich weiß, werden statische Zuweisungen solcher Ressourcen vom Klassenlader als threadsicher garantiert. Die Logger-Instanz ist unabhängig davon, wo Sie den Zeiger zuweisen, threadsicher oder nicht. Es ist wahrscheinlich keine gute Idee, den Status in der Statik beizubehalten, aber es gibt keinen Grund, warum er nicht threadsicher sein sollte.
Teknopaul

29

Wenn Sie das Schlüsselwort 'static' ohne das Schlüsselwort 'final' verwenden, sollte dies ein Signal sein, um Ihr Design sorgfältig zu prüfen. Selbst das Vorhandensein eines "Finales" ist kein Freipass, da ein veränderbares statisches Endobjekt genauso gefährlich sein kann.

Ich würde schätzen, dass ungefähr 85% der Zeit, in der ich eine "Statik" ohne "Finale" sehe, FALSCH ist. Oft finde ich seltsame Problemumgehungen, um diese Probleme zu maskieren oder zu verbergen.

Bitte erstellen Sie keine statischen Mutables. Besonders Sammlungen. Im Allgemeinen sollten Sammlungen initialisiert werden, wenn ihr enthaltendes Objekt initialisiert wird, und sollten so gestaltet sein, dass sie zurückgesetzt oder vergessen werden, wenn ihr enthaltendes Objekt vergessen wird.

Die Verwendung von Statik kann zu sehr subtilen Fehlern führen, die den Ingenieuren tagelang Schmerzen bereiten. Ich weiß, weil ich diese Bugs sowohl erstellt als auch gejagt habe.

Wenn Sie weitere Informationen wünschen, lesen Sie bitte weiter…

Warum nicht Statik verwenden?

Es gibt viele Probleme mit der Statik, einschließlich des Schreibens und Ausführens von Tests sowie subtile Fehler, die nicht sofort offensichtlich sind.

Code, der auf statischen Objekten basiert, kann nicht einfach in Einheiten getestet werden, und Statik kann (normalerweise) nicht einfach verspottet werden.

Wenn Sie Statik verwenden, ist es nicht möglich, die Implementierung der Klasse auszutauschen, um übergeordnete Komponenten zu testen. Stellen Sie sich beispielsweise ein statisches CustomerDAO vor, das Kundenobjekte zurückgibt, die es aus der Datenbank lädt. Jetzt habe ich eine Klasse CustomerFilter, die auf einige Kundenobjekte zugreifen muss. Wenn CustomerDAO statisch ist, kann ich keinen Test für CustomerFilter schreiben, ohne zuerst meine Datenbank zu initialisieren und nützliche Informationen auszufüllen.

Das Auffüllen und Initialisieren der Datenbank dauert lange. Und meiner Erfahrung nach wird sich Ihr DB-Initialisierungsframework im Laufe der Zeit ändern, was bedeutet, dass sich Daten ändern und Tests möglicherweise unterbrochen werden. Stellen Sie sich vor, Kunde 1 war früher ein VIP, aber das DB-Initialisierungsframework hat sich geändert, und jetzt ist Kunde 1 kein VIP mehr, aber Ihr Test war fest codiert, um Kunde 1 zu laden.

Ein besserer Ansatz besteht darin, ein CustomerDAO zu instanziieren und es beim Erstellen an den CustomerFilter zu übergeben. (Ein noch besserer Ansatz wäre die Verwendung von Spring oder eines anderen Inversion of Control-Frameworks.

Sobald Sie dies getan haben, können Sie schnell ein alternatives DAO in Ihrem CustomerFilterTest verspotten oder auslöschen, sodass Sie mehr Kontrolle über den Test haben.

Ohne das statische DAO ist der Test schneller (keine Datenbankinitialisierung) und zuverlässiger (da er nicht fehlschlägt, wenn sich der Datenbankinitialisierungscode ändert). In diesem Fall muss beispielsweise sichergestellt werden, dass Kunde 1 ein VIP ist und immer sein wird, was den Test betrifft.

Ausführen von Tests

Die Statik verursacht ein echtes Problem, wenn mehrere Komponententests zusammen ausgeführt werden (z. B. mit Ihrem Continuous Integration-Server). Stellen Sie sich eine statische Karte von Netzwerk-Socket-Objekten vor, die von einem Test zum anderen geöffnet bleibt. Der erste Test öffnet möglicherweise einen Socket an Port 8080, aber Sie haben vergessen, die Karte zu löschen, wenn der Test abgerissen wird. Wenn jetzt ein zweiter Test gestartet wird, stürzt er wahrscheinlich ab, wenn versucht wird, einen neuen Socket für Port 8080 zu erstellen, da der Port noch belegt ist. Stellen Sie sich außerdem vor, dass Socket-Referenzen in Ihrer statischen Sammlung nicht entfernt werden und (mit Ausnahme von WeakHashMap) niemals zur Speicherbereinigung berechtigt sind, was zu einem Speicherverlust führt.

Dies ist ein übermäßig verallgemeinertes Beispiel, aber in großen Systemen tritt dieses Problem STÄNDIG auf. Die Leute denken nicht daran, dass Unit-Tests ihre Software wiederholt in derselben JVM starten und stoppen, aber es ist ein guter Test für Ihr Software-Design, und wenn Sie Bestrebungen nach hoher Verfügbarkeit haben, müssen Sie sich dessen bewusst sein.

Diese Probleme treten häufig bei Framework-Objekten auf, z. B. bei den Ebenen DB-Zugriff, Caching, Messaging und Protokollierung. Wenn Sie Java EE oder einige der besten Frameworks verwenden, verwalten diese wahrscheinlich viel davon für Sie, aber wenn Sie wie ich mit einem Legacy-System arbeiten, haben Sie möglicherweise viele benutzerdefinierte Frameworks, um auf diese Ebenen zuzugreifen.

Wenn sich die Systemkonfiguration, die für diese Framework-Komponenten gilt, zwischen Komponententests ändert und das Unit-Test-Framework die Komponenten nicht herunterfährt und neu erstellt, können diese Änderungen nicht wirksam werden. Wenn ein Test auf diesen Änderungen beruht, schlagen sie fehl .

Auch Nicht-Framework-Komponenten sind diesem Problem ausgesetzt. Stellen Sie sich eine statische Karte namens OpenOrders vor. Sie schreiben einen Test, der einige offene Aufträge erstellt, und prüfen, ob alle im richtigen Zustand sind. Anschließend endet der Test. Ein anderer Entwickler schreibt einen zweiten Test, der die benötigten Bestellungen in die OpenOrders-Karte einfügt und dann bestätigt, dass die Anzahl der Bestellungen korrekt ist. Diese Tests werden einzeln ausgeführt und bestehen beide. Wenn sie jedoch zusammen in einer Suite ausgeführt werden, schlagen sie fehl.

Schlimmer noch, ein Fehler kann auf der Reihenfolge basieren, in der die Tests ausgeführt wurden.

In diesem Fall vermeiden Sie durch die Vermeidung von Statik das Risiko, dass Daten über Testinstanzen hinweg erhalten bleiben, und gewährleisten so eine bessere Testzuverlässigkeit.

Subtile Fehler

Wenn Sie in einer Hochverfügbarkeitsumgebung oder an einem Ort arbeiten, an dem Threads möglicherweise gestartet und gestoppt werden, kann das oben erwähnte Problem mit Unit-Test-Suites auch dann auftreten, wenn Ihr Code in der Produktion ausgeführt wird.

Wenn Sie mit Threads arbeiten, anstatt ein statisches Objekt zum Speichern von Daten zu verwenden, ist es besser, ein Objekt zu verwenden, das während der Startphase des Threads initialisiert wurde. Auf diese Weise wird jedes Mal, wenn der Thread gestartet wird, eine neue Instanz des Objekts (mit einer möglicherweise neuen Konfiguration) erstellt, und Sie vermeiden, dass Daten von einer Instanz des Threads zur nächsten Instanz durchbluten.

Wenn ein Thread stirbt, wird ein statisches Objekt nicht zurückgesetzt oder Müll gesammelt. Stellen Sie sich vor, Sie haben einen Thread namens "EmailCustomers". Wenn er gestartet wird, wird eine statische String-Sammlung mit einer Liste von E-Mail-Adressen gefüllt und anschließend jede der Adressen per E-Mail gesendet. Nehmen wir an, der Thread wird unterbrochen oder irgendwie abgebrochen, sodass Ihr Hochverfügbarkeits-Framework den Thread neu startet. Wenn der Thread gestartet wird, wird die Kundenliste neu geladen. Da die Sammlung jedoch statisch ist, wird möglicherweise die Liste der E-Mail-Adressen aus der vorherigen Sammlung beibehalten. Jetzt erhalten einige Kunden möglicherweise doppelte E-Mails.

Nebenbei: Statisches Finale

Die Verwendung von "static final" ist effektiv das Java-Äquivalent einer C # -Definition, obwohl es technische Implementierungsunterschiede gibt. AC / C ++ #define wird vor der Kompilierung vom Vorprozessor aus dem Code ausgelagert. Ein Java "statisches Finale" wird am Ende auf dem Stapel gespeichert. Auf diese Weise ähnelt es eher einer "statischen const" -Variablen in C ++ als einer #define.

Zusammenfassung

Ich hoffe, dies erklärt einige grundlegende Gründe, warum Statik problematisch ist. Wenn Sie ein modernes Java-Framework wie Java EE oder Spring usw. verwenden, treten möglicherweise nicht viele dieser Situationen auf. Wenn Sie jedoch mit einer großen Anzahl von Legacy-Code arbeiten, können diese viel häufiger auftreten.


15

Da hat es niemand * erwähnt: Parallelität. Statische Variablen können Sie überraschen, wenn mehrere Threads in die statische Variable lesen und schreiben. Dies ist in Webanwendungen (z. B. ASP.NET) häufig und kann einige ziemlich verrückte Fehler verursachen. Wenn Sie beispielsweise eine statische Variable haben, die von einer Seite aktualisiert wird, und die Seite "fast zur gleichen Zeit" von zwei Personen angefordert wird, erhält ein Benutzer möglicherweise das vom anderen Benutzer erwartete Ergebnis oder noch schlimmer.

Statik reduziert die gegenseitigen Abhängigkeiten von den anderen Teilen des Codes. Sie können als perfekte Staatsinhaber auftreten

Ich hoffe, Sie sind bereit, Schlösser zu verwenden und mit Konflikten umzugehen.

* Eigentlich hat Preet Sangha es erwähnt.


5
Instanzvariablen haben keine Vorteile für die Thread-Sicherheit gegenüber der Statik. Sie sind alle ungeschützte Variablen. Stattdessen kommt es darauf an, wie Sie den Code schützen, der auf diese Variablen zugreift.
Studgeek

2
Ich habe diese Behauptung nicht ganz aufgestellt, aber zur Diskussion: Trennung ist eine Form des Schutzes. Thread-Zustände werden getrennt; globaler Zustand ist nicht . Eine Instanz Variable nicht braucht Schutz , wenn es ausdrücklich zwischen Threads gemeinsam genutzt werden ; Eine statische Variable wird immer von allen Threads im Prozess gemeinsam genutzt.
Justin M. Keyes

Ich wünschte, thread-statische Variablen wären eher ein erstklassiges Konzept, da sie sehr nützlich sein können, um Informationen sicher für einen umschlossenen Unterprogrammaufruf verfügbar zu machen, ohne diese Informationen durch jede Umhüllungsebene weiterleiten zu müssen. Wenn ein Objekt beispielsweise Methoden zum Rendern im aktuellen Grafikkontext des Threads hatte und es Methoden zum Speichern / Wiederherstellen des aktuellen Grafikkontexts gab, war die Verwendung dieser Methoden häufig sauberer, als wenn der Grafikkontext bei jedem Methodenaufruf übergeben werden musste.
Supercat

15

Einige grundlegende Vor- und Nachteile der Verwendung statischer Methoden in Java zusammenfassen:

Vorteile:

  1. Weltweit zugänglich, dh nicht an eine bestimmte Objektinstanz gebunden.
  2. Eine Instanz pro JVM.
  3. Zugriff über den Klassennamen (kein Objekt erforderlich).
  4. Enthält einen einzelnen Wert, der für alle Instanzen gilt.
  5. Wird beim Start der JVM geladen und stirbt, wenn die JVM heruntergefahren wird.
  6. Sie ändern den Status des Objekts nicht.

Nachteile:

  1. Statische Elemente sind immer Teil des Speichers, unabhängig davon, ob sie verwendet werden oder nicht.
  2. Sie können die Erstellung und Zerstörung statischer Variablen nicht steuern. Nützlicherweise wurden sie beim Laden des Programms erstellt und beim Entladen des Programms (oder beim Herunterfahren von JVM) zerstört.
  3. Sie können den statischen Thread mithilfe der Synchronisierung sicher machen, benötigen jedoch einige zusätzliche Anstrengungen.
  4. Wenn ein Thread den Wert einer statischen Variablen ändert, kann dies möglicherweise die Funktionalität anderer Threads beeinträchtigen.
  5. Sie müssen "statisch" kennen, bevor Sie es verwenden.
  6. Sie können statische Methoden nicht überschreiben.
  7. Die Serialisierung funktioniert mit ihnen nicht gut.
  8. Sie nehmen nicht am Laufzeitpolymorphismus teil.
  9. Es gibt ein Speicherproblem (bis zu einem gewissen Grad, aber nicht viel, denke ich), wenn eine große Anzahl statischer Variablen / Methoden verwendet wird. Weil sie erst nach Programmende gesammelt werden.
  10. Statische Methoden sind ebenfalls schwer zu testen.

Die Nachteile 6, 7, 8 und 10 sind die Nachteile der verwendeten Sprachen / Frameworks und nicht die Nachteile der statischen Variablen im Allgemeinen. Die Nachteile 1, 4 und 5 bestehen auch für andere Lösungen, wie zum Beispiel ein Singleton-Muster, das von einem Framework bereitgestellt wird. (Ich habe nicht für die Antwort gestimmt, weil ich dem Rest zustimme und es eine schöne Sammlung ist.)
Peter - Reinstate Monica

13

Wenn ich 10.000 Aufrufe an eine Funktion innerhalb einer Klasse ausführen müsste, würde ich die Methode gerne statisch machen und eine einfache class.methodCall () verwenden, anstatt den Speicher mit 10.000 Instanzen der Klasse zu überladen, oder?

Sie müssen die Notwendigkeit, Daten in ein Objekt mit einem Status zu kapseln, gegen die Notwendigkeit abwägen, das Ergebnis einer Funktion für einige Daten einfach zu berechnen.

Darüber hinaus reduzieren Statiken die gegenseitigen Abhängigkeiten von den anderen Teilen des Codes.

Kapselung auch. In großen Anwendungen erzeugt die Statik in der Regel Spaghetti-Code und ermöglicht kein leichtes Refactoring oder Testen.

Die anderen Antworten liefern ebenfalls gute Gründe gegen einen übermäßigen Einsatz von Statik.


13

Statische Variablen werden im Allgemeinen als schlecht angesehen, da sie den globalen Zustand darstellen und daher viel schwieriger zu begründen sind. Insbesondere brechen sie die Annahmen der objektorientierten Programmierung. Bei der objektorientierten Programmierung hat jedes Objekt seinen eigenen Status, der durch Instanzvariablen (nicht statisch) dargestellt wird. Statische Variablen repräsentieren den Zustand über Instanzen hinweg, was für Unit-Tests viel schwieriger sein kann. Dies liegt hauptsächlich daran, dass es schwieriger ist, Änderungen an statischen Variablen in einem einzigen Test zu isolieren.

Abgesehen davon ist es wichtig, zwischen regulären statischen Variablen (allgemein als schlecht angesehen) und endgültigen statischen Variablen (AKA-Konstanten; nicht so schlecht) zu unterscheiden.


4
"Statische Variablen repräsentieren den Status über Klassen hinweg" ... Ich denke, Sie meinen "statische Variablen repräsentieren den Status über Instanzen hinweg"? +1 für "endgültige statische AKA-Konstanten, nicht so schlecht". Da sich der Wert nicht ändern kann, kann alles, was zu einem bestimmten Zeitpunkt davon abhängt, sein Verhalten zu einem späteren Zeitpunkt nicht implizit ändern - der Wert ist der gleiche.
Jared Updike

"Statische Variablen repräsentieren den Zustand über Instanzen hinweg" ist eine viel bessere Möglichkeit, dies anzugeben. Ich habe meine Antwort bearbeitet.
Jack Edmonds

9

Meiner Meinung nach geht es kaum um Leistung, sondern um Design. Ich halte die Verwendung statischer Methoden nicht für falsch, da statische Variablen verwendet werden (aber ich denke, Sie sprechen tatsächlich von Methodenaufrufen).

Es geht einfach darum, Logik zu isolieren und ihr einen guten Platz zu geben. Manchmal rechtfertigt dies die Verwendung statischer Methoden, wofür java.lang.Mathein gutes Beispiel ist. Ich denke, wenn Sie die meisten Ihrer Klassen benennen XxxUtiloder XxxhelperIhr Design besser überdenken sollten.


3
Reine nebenwirkungsfreie statische Methoden sind IMO vollkommen in Ordnung. Aber global veränderlicher Zustand ist selten und ich interpretiere das OP so, dass es über globalen Zustand spricht.
CodesInChaos

1
@ CodeInChaos stimmen voll und ganz zu. Ich finde, das OP ist nicht ganz klar über den Unterschied zwischen statischen Methoden und Vars.
M Platvoet

8

Ich habe gerade einige der in den Antworten gemachten Punkte zusammengefasst. Wenn Sie etwas falsch finden, können Sie es gerne korrigieren.

Skalierung: Wir haben genau eine Instanz einer statischen Variablen pro JVM. Angenommen, wir entwickeln ein Bibliotheksverwaltungssystem und haben beschlossen, den Namen des Buches als statische Variable festzulegen, da es nur eine pro Buch gibt. Aber wenn das System wächst und wir mehrere JVMs verwenden, haben wir keine Möglichkeit herauszufinden, mit welchem ​​Buch wir es zu tun haben?

Thread-Sicherheit: Sowohl Instanzvariable als auch statische Variable müssen gesteuert werden, wenn sie in einer Umgebung mit mehreren Threads verwendet werden. Bei einer Instanzvariablen ist jedoch kein Schutz erforderlich, es sei denn, sie wird explizit von Threads gemeinsam genutzt. Bei einer statischen Variablen wird sie jedoch immer von allen Threads im Prozess gemeinsam genutzt.

Testen: Obwohl testbares Design nicht gleich gutes Design ist, werden wir selten ein gutes Design beobachten, das nicht testbar ist. Da statische Variablen den globalen Zustand darstellen und es sehr schwierig wird, sie zu testen.

Begründung zum Status: Wenn ich eine neue Instanz einer Klasse erstelle, können wir den Status dieser Instanz begründen. Wenn sie jedoch statische Variablen enthält, kann sie sich in einem beliebigen Status befinden. Warum? Weil es möglich ist, dass die statische Variable von einer anderen Instanz geändert wurde, da die statische Variable von mehreren Instanzen gemeinsam genutzt wird.

Serialisierung: Die Serialisierung funktioniert auch nicht gut mit ihnen.

Erzeugung und Zerstörung: Die Erzeugung und Zerstörung statischer Variablen kann nicht gesteuert werden. Normalerweise werden sie beim Laden und Entladen des Programms erstellt und zerstört. Dies bedeutet, dass sie für die Speicherverwaltung schlecht sind und auch die Initialisierungszeit beim Start addieren.

Aber was ist, wenn wir sie wirklich brauchen?

Aber manchmal brauchen wir sie wirklich. Wenn wir wirklich das Bedürfnis nach vielen statischen Variablen haben, die in der gesamten Anwendung gemeinsam genutzt werden, besteht eine Option darin, das Singleton-Entwurfsmuster zu verwenden, das alle diese Variablen enthält. Oder wir können ein Objekt erstellen, das diese statische Variable enthält und weitergegeben werden kann.

Auch wenn die statische Variable als endgültig markiert ist, wird sie zu einer Konstante und der ihr einmal zugewiesene Wert kann nicht geändert werden. Es bedeutet, dass es uns vor allen Problemen bewahren wird, mit denen wir aufgrund seiner Veränderlichkeit konfrontiert sind.


7

Mir scheint, Sie fragen nach statischen Variablen, aber Sie weisen in Ihren Beispielen auch auf statische Methoden hin.

Statische Variablen sind nicht böse - sie werden in den meisten Fällen als globale Variablen wie Konstanten in Kombination mit dem endgültigen Modifikator verwendet, aber wie gesagt, verwenden Sie sie nicht übermäßig.

Statische Methoden, auch als Utility-Methode bezeichnet. Es ist im Allgemeinen keine schlechte Praxis, sie zu verwenden, aber die größte Sorge ist, dass sie das Testen behindern könnten .

Als Beispiel für ein großartiges Java-Projekt, das viel Statik verwendet und es richtig macht, schauen Sie sich bitte Play! Rahmen . Es gibt auch Diskussionen darüber in SO.

Statische Variablen / Methoden in Kombination mit statischem Import werden auch häufig in Bibliotheken verwendet, die die deklarative Programmierung in Java erleichtern, z . B .: Make it easy oder Hamcrest . Ohne viele statische Variablen und Methoden wäre dies nicht möglich.

Statische Variablen (und Methoden) sind also gut, aber setzen Sie sie mit Bedacht ein!


6

Statische Variablen verursachen vor allem Probleme mit der Datensicherheit (jederzeit geändert, jeder kann Änderungen vornehmen, direkter Zugriff ohne Objekt usw.)

Für weitere Informationen lesen Sie diesen Dank.


6

Es kann vorgeschlagen werden, dass Sie in den meisten Fällen, in denen Sie eine statische Variable verwenden, wirklich das Singleton-Muster verwenden möchten .

Das Problem mit globalen Zuständen ist, dass manchmal das, was in einem einfacheren Kontext als global sinnvoll ist, in einem praktischen Kontext etwas flexibler sein muss, und hier wird das Singleton-Muster nützlich.


5

Noch ein Grund: Zerbrechlichkeit.

Wenn Sie eine Klasse haben, erwarten die meisten Leute, dass Sie sie erstellen und nach Belieben verwenden können.

Sie können dokumentieren, dass dies nicht der Fall ist, oder sich davor schützen (Singleton- / Factory-Muster) - aber das ist zusätzliche Arbeit und daher zusätzliche Kosten. Selbst dann, in einem großen Unternehmen, besteht die Möglichkeit, dass irgendwann jemand versucht, Ihre Klasse zu nutzen, ohne all die netten Kommentare oder die Fabrik vollständig zu beachten.

Wenn Sie häufig statische Variablen verwenden, wird dies nicht funktionieren. Bugs sind teuer.

Zwischen einer Leistungsverbesserung von 0,0001% und der Robustheit gegenüber Änderungen durch potenziell ahnungslose Entwickler ist in vielen Fällen die Robustheit die gute Wahl.


4

Ich finde statische Variablen bequemer zu verwenden. Und ich gehe davon aus, dass sie auch effizient sind (bitte korrigieren Sie mich, wenn ich falsch liege), denn wenn ich 10.000 Aufrufe einer Funktion innerhalb einer Klasse durchführen müsste, würde ich die Methode gerne statisch machen und eine einfache class.methodCall () verwenden. darauf, anstatt den Speicher mit 10.000 Instanzen der Klasse zu überladen, richtig?

Ich verstehe, was Sie denken, aber ein einfaches Singleton-Muster macht dasselbe, ohne 10 000 Objekte instanziieren zu müssen.

statische Methoden können verwendet werden, jedoch nur für Funktionen, die sich auf die Objektdomäne beziehen und keine internen Eigenschaften des Objekts benötigen oder verwenden.

Ex:

public class WaterContainer {
    private int size;
    private int brand;
    ...etc

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}

Ein klassischer Singleton (dh einer, auf den zugegriffen wird Class.Instance) ist kaum besser als eine statische Variable. Es ist etwas testbarer, aber immer noch viel schlimmer als Designs, bei denen Sie zufällig eine einzelne Instanz erstellen, anstatt Ihren Code unter der Annahme zu erstellen, dass es nur eine gibt.
CodesInChaos

Ich bin mir nicht sicher, ob ich deinen Kommentar verstehe! Ich antwortete dem OP über das, was er kursiv über die Instanziierung von 10 000 Objekten sagte. Ich verstehe nicht, warum Sie einen Singleton und eine statische Variable vergleichen? Was ich aus dem, was Sie geschrieben haben, verstehe, ist, dass Singleton schlechtes Design ist ...! Ich denke, ich verstehe dich falsch, da das Spring Framework standardmäßig alle Bohnen Singleton macht ;-)
Cygnusx1

Ein klassischer Singleton (der hat Class.Instance), der einen veränderlichen Zustand trägt, ist schlechtes Design IMO. In diesem Fall bevorzuge ich dringend ein Design, bei dem die Singletons, die ich verwenden muss, als Parameter an die Klasse übergeben werden, die sie verwendet (normalerweise mit Hilfe von DI). Logisch unveränderliche klassische Singletons sind IMO in Ordnung.
CodesInChaos

@ Cygnusx1 Falls nicht klar war, warum ein Klassen-Singleton (ein Singleton, bei dem die Klasse sicherstellt, dass es sich um eine einzelne Kopie handelt) nicht einfach zu testen ist, wird die Klassenexistenz eng mit dem Lebenszyklus des Programms verknüpft. Um es zu testen, müssen Sie sich an den Start und das Herunterfahren des Programms halten, was häufig Nebenwirkungen hat, die für das Testen der Klasse unwichtig sind. Wenn es sich effektiv um ein Singleton handelt (eine Kopie im Programm, ansonsten jedoch keine Durchsetzung), können Sie zum Testzeitpunkt mehrere Kopien ohne das Programm erstellen und überprüfen, ob das Verhalten in der gesamten Klasse für jedes Testszenario so ist, wie es sein sollte.
Edwin Buck

4

Das Thema "Statik ist böse" ist eher ein Thema des globalen Staates. Die geeignete Zeit für eine statische Variable ist, wenn sie nie mehr als einen Zustand hat. IE-Tools, auf die das gesamte Framework zugreifen sollte und die immer dieselben Ergebnisse für dieselben Methodenaufrufe zurückgeben, sind niemals "böse" wie die Statik. Zu Ihrem Kommentar:

Ich finde statische Variablen bequemer zu verwenden. Und ich gehe davon aus, dass sie auch effizient sind

Statik ist die ideale und effiziente Wahl für Variablen / Klassen, die sich nie ändern .

Das Problem mit dem globalen Zustand ist die inhärente Inkonsistenz, die er erzeugen kann. In der Dokumentation zu Komponententests wird dieses Problem häufig behoben, da Ihre Komponententests immer dann unvollständig und nicht "einheitlich" sind, wenn ein globaler Status vorliegt, auf den mehr als mehrere nicht verwandte Objekte zugreifen können. Wie in diesem Artikel über den globalen Zustand und Singletons erwähnt , sollte A den Zustand von B nicht beeinflussen können, wenn Objekt A und B nicht miteinander verwandt sind (da in einem Objekt nicht ausdrücklich auf ein anderes Bezug genommen wird).

Es gibt einige Ausnahmen zum Verbot des globalen Zustands in gutem Code, wie z. B. die Uhr. Zeit ist global und ändert in gewissem Sinne den Zustand von Objekten, ohne eine codierte Beziehung zu haben.


"Zeit ist global" - es gibt andere Möglichkeiten, die Zeit in Computersystemen zu modellieren, als eine implizite, globale Sache zu sein, die sich von selbst ändert. vgl. diese Umfrage: "Modellierungszeit in Computing: Eine Taxonomie und eine vergleichende Umfrage" @ arxiv.org/abs/0807.4132
Jared Updike

4

Mein $ .02 ist, dass einige dieser Antworten das Problem verwirren, anstatt zu sagen, dass "Statik schlecht ist". Ich denke, es ist besser, über Umfang und Instanzen zu sprechen.

Was ich sagen würde, ist, dass eine Statik eine "Klassen" -Variable ist - sie repräsentiert einen Wert, der von allen Instanzen dieser Klasse gemeinsam genutzt wird. Normalerweise sollte der Umfang auch so sein (geschützt oder privat für die Klasse und ihre Instanzen).

Wenn Sie vorhaben, das Verhalten auf Klassenebene zu umgehen und es anderem Code auszusetzen, ist ein Singleton möglicherweise die bessere Lösung, um zukünftige Änderungen zu unterstützen (wie von @Jessica vorgeschlagen). Dies liegt daran, dass Sie Schnittstellen auf Instanz- / Singleton-Ebene auf eine Weise verwenden können, die Sie auf Klassenebene nicht verwenden können - insbesondere bei der Vererbung.

Einige Gedanken darüber, warum ich denke, dass einige Aspekte in anderen Antworten nicht der Kern der Frage sind ...

Statik ist nicht "global". In Java wird das Scoping getrennt von static / instance gesteuert.

Parallelität ist für die Statik nicht weniger gefährlich als Instanzmethoden. Es ist immer noch ein Zustand, der geschützt werden muss. Sicher, Sie haben vielleicht 1000 Instanzen mit jeweils einer Instanzvariablen und nur einer statischen Variablen, aber wenn der Code, auf den auf eine der beiden zugegriffen wird, nicht threadsicher geschrieben ist, sind Sie immer noch geschraubt - es kann nur etwas länger dauern, bis Sie ihn realisieren .

Das Management des Lebenszyklus ist ein interessantes Argument, aber ich denke, es ist weniger wichtig. Ich verstehe nicht, warum es schwieriger ist, ein Paar von Klassenmethoden wie init () / clear () zu verwalten, als eine Singleton-Instanz zu erstellen und zu zerstören. Einige könnten sogar sagen, dass ein Singleton aufgrund von GC etwas komplizierter ist.

PS: In Bezug auf Smalltalk haben viele seiner Dialekte Klassenvariablen, aber in Smalltalk sind Klassen tatsächlich Instanzen von Metaclass, also tatsächlich Variablen in der Metaclass-Instanz. Trotzdem würde ich die gleiche Faustregel anwenden. Wenn sie instanzübergreifend für den gemeinsamen Status verwendet werden, ist dies in Ordnung. Wenn sie öffentliche Funktionen unterstützen, sollten Sie sich einen Singleton ansehen. Seufz, ich vermisse Smalltalk wirklich ...


4

Ihr Beitrag enthält zwei Hauptfragen.

Zunächst zu statischen Variablen. Statische Variablen sind völlig unnötig und ihre Verwendung kann leicht vermieden werden. In OOP-Sprachen im Allgemeinen und in Java im Besonderen werden Funktionsparameter als Referenz angegeben. Wenn Sie also ein Objekt an eine Funktion übergeben, übergeben Sie einen Zeiger auf das Objekt, sodass Sie seitdem keine statischen Variablen definieren müssen Sie können einen Zeiger auf das Objekt an einen beliebigen Bereich übergeben, der diese Informationen benötigt. Selbst wenn dies impliziert, dass Sie Ihren Speicher mit Zeigern füllen, stellt dies keine schlechte Leistung dar, da die tatsächlichen Speicher-Pagging-Systeme dafür optimiert sind und die Seiten, auf die durch die Zeiger verwiesen wird, die Sie an die neuen übergeben haben, im Speicher bleiben Umfang; Die Verwendung statischer Variablen kann dazu führen, dass das System die Speicherseite lädt, auf der sie gespeichert sind, wenn auf sie zugegriffen werden muss (dies geschieht, wenn die Seite längere Zeit nicht aufgerufen wurde). Eine gute Vorgehensweise besteht darin, all diese statischen Daten in einigen kleinen "Konfigurationsklassen" zusammenzufassen. Dadurch wird sichergestellt, dass das System alles auf derselben Speicherseite ablegt.

Zweitens über statische Methoden. Statische Methoden sind nicht so schlecht, können aber die Leistung schnell reduzieren. Stellen Sie sich beispielsweise eine Methode vor, die zwei Objekte einer Klasse vergleicht und einen Wert zurückgibt, der angibt, welches der Objekte größer ist (typische Vergleichsmethode). Diese Methode kann statisch sein oder nicht. Beim Aufrufen ist die nicht statische Form jedoch effizienter da nur zwei Referenzen (eine für jedes Objekt) zu den drei Referenzen aufgelöst werden müssen, die die statische Version derselben Methode lösen müssen (eine für die Klasse plus zwei, eine für jedes Objekt). Aber wie gesagt, das ist nicht so schlimm. Wenn wir uns die Matheklasse ansehen, können wir viele Mathefunktionen finden, die als statische Methoden definiert sind. Dies ist wirklich effizienter, als alle diese Methoden in die Klasse aufzunehmen, die die Zahlen definiert.

Fazit: Vermeiden Sie die Verwendung statischer Variablen und finden Sie das richtige Leistungsgleichgewicht, wenn Sie mit statischen oder nicht statischen Methoden arbeiten.

PS: Entschuldigung für mein Englisch.


4

An statischen Variablen an sich ist nichts auszusetzen. Es ist nur die Java-Syntax, die kaputt ist. Jede Java-Klasse definiert tatsächlich zwei Strukturen - ein Singleton-Objekt, das statische Variablen kapselt, und eine Instanz. Das Definieren beider im selben Quellblock ist absolut böse und führt zu einem Code, der schwer zu lesen ist. Scala hat das richtig gemacht.


3

a) Grund für Programme.

Wenn Sie ein kleines bis mittelgroßes Programm haben, in dem auf die statische Variable Global.foo zugegriffen wird, kommt der Aufruf normalerweise aus dem Nichts - es gibt keinen Pfad und daher keine Zeitleiste, wie die Variable an den Ort kommt, an dem sie sich befindet wird genutzt. Woher weiß ich nun, wer es auf seinen tatsächlichen Wert gesetzt hat? Woher weiß ich, was passiert, wenn ich es gerade ändere? Ich habe über die gesamte Quelle grep, um alle Zugriffe zu sammeln, um zu wissen, was los ist.

Wenn Sie wissen, wie Sie es verwenden, weil Sie gerade den Code geschrieben haben, ist das Problem unsichtbar. Wenn Sie jedoch versuchen, Fremdcode zu verstehen, werden Sie verstehen.

b) Brauchen Sie wirklich nur einen?

Statische Variablen verhindern häufig, dass mehrere Programme derselben Art in derselben JVM mit unterschiedlichen Werten ausgeführt werden. Sie sehen häufig keine Verwendungen voraus, bei denen mehr als eine Instanz Ihres Programms nützlich ist. Wenn sich diese jedoch weiterentwickelt oder wenn sie für andere nützlich ist, kann es zu Situationen kommen, in denen sie mehr als eine Instanz Ihres Programms starten möchten .

Nur mehr oder weniger nutzloser Code, der von vielen Menschen über einen längeren Zeitraum nicht intensiv verwendet wird, passt möglicherweise gut zu statischen Variablen.


3

Alles (kann :) seinen Zweck haben, wenn Sie eine Reihe von Threads haben, die Daten gemeinsam nutzen / zwischenspeichern müssen , sowie den gesamten verfügbaren Speicher (damit Sie nicht in Kontexte innerhalb einer JVM aufgeteilt werden), ist die statische Aufladung die beste Wahl

-> natürlich können Sie dies erzwingen nur eine Instanz, aber warum?
Ich finde einige der Kommentare in diesem Thread böse, nicht die Statik;)


3

Statische Variablen sind weder gut noch böse. Sie stellen Attribute dar, die die gesamte Klasse und keine bestimmte Instanz beschreiben. Wenn Sie einen Zähler für alle Instanzen einer bestimmten Klasse benötigen, ist eine statische Variable der richtige Ort, um den Wert zu speichern.

Probleme treten auf, wenn Sie versuchen, statische Variablen zum Speichern instanzbezogener Werte zu verwenden.


2

Alle obigen Antworten zeigen, warum die Statik schlecht ist. Der Grund, warum sie böse sind, ist, dass sie den falschen Eindruck erwecken, dass Sie objektorientierten Code schreiben, obwohl dies nicht der Fall ist. Das ist einfach nur böse.


1
Aber macht es den Code tatsächlich besser, wenn Sie Ihren Code streng nach einem beliebigen Standardparadigma betrachten, oder beschweren wir uns, nicht nur Code zu schreiben, der funktioniert?
Zoey

Ja, es macht es besser, weil es in Zukunft leichter zu handhaben, leichter zu verstehen und expliziter ist.
Dummkopf

1
Warum ist es böse, keinen OO-Code zu schreiben? und warum stimmt Bjarne Stroustrup Ihnen nicht zu? um nur einen zu nennen ...
Marquis von Lorne

2
Ich habe nicht gesagt, dass es böse ist, keinen OO-Code zu schreiben. Ich sagte, es ist böse zu glauben, dass Sie OO-Code schreiben, wenn Sie nur Globale hinter statischen Methoden und Eigenschaften verschleiern. Bitte lesen Sie noch einmal, was ich geschrieben habe.
Dummkopf

2

Hier gibt es viele gute Antworten, die dazu beitragen,

Speicher: Statische Variablen sind so lange aktiv, wie der Klassenlader [im Allgemeinen bis zum Absterben der VM] aktiv ist. Dies gilt jedoch nur für als statisch gespeicherte Massenobjekte / Referenzen.

Modularisierung: Berücksichtigen Sie Konzepte wie IOC, DependencyInjection, Proxy usw. Alle sind vollständig gegen eng gekoppelte / statische Implementierungen.

Andere Nachteile: Gewindesicherheit, Testbarkeit


0

Wenn Sie eine Anwendung mit vielen Benutzern haben und ein statisches Formular definiert haben, ändert jeder Benutzer auch alle anderen Formulare anderer Benutzer.


0

Ich denke, dass eine übermäßige Verwendung globaler Variablen mit statischem Schlüsselwort auch zu einem Speicherverlust an einem bestimmten Punkt in der Anwendung führt


0

Aus meiner Sicht staticsollten Variablen nur schreibgeschützte Daten oder Variablen sein, die durch Konventionen erstellt wurden .

Zum Beispiel haben wir eine Benutzeroberfläche eines Projekts und eine Liste von Ländern, Sprachen, Benutzerrollen usw. Und wir haben eine Klasse, um diese Daten zu organisieren. Wir sind absolut sicher, dass die App ohne diese Listen nicht funktioniert. Das erste, was wir bei App Init tun, ist, diese Liste auf Updates zu überprüfen und diese Liste von der API abzurufen (falls erforderlich). Wir sind uns also einig, dass diese Daten "immer" in der App vorhanden sind. Es handelt sich praktisch nur um schreibgeschützte Daten, sodass wir uns nicht um den Status kümmern müssen. Wenn wir über diesen Fall nachdenken, möchten wir wirklich nicht viele Instanzen dieser Daten haben. Dieser Fall scheint ein perfekter Kandidat zu sein, um statisch zu sein .


0

Ich habe viel mit Statik gespielt und darf ich Ihnen eine etwas andere Antwort geben - oder vielleicht eine etwas andere Sichtweise?

Wenn ich Statik in einer Klasse verwendet habe (Mitglieder und Methoden beide), bemerkte ich schließlich, dass meine Klasse tatsächlich zwei Klassen ist, die die Verantwortung teilen - es gibt den "statischen" Teil, der sich sehr ähnlich wie ein Singleton verhält, und den Nicht-Teil -statischer Teil (eine normale Klasse). Soweit ich weiß, können Sie diese beiden Klassen immer vollständig trennen, indem Sie einfach alle Statiken für eine Klasse und Nicht-Statiken für die andere auswählen.

Dies geschah häufig, wenn ich eine statische Sammlung in einer Klasse hatte, die Instanzen der Klasse und einige statische Methoden zum Verwalten der Sammlung enthielt. Wenn Sie einmal darüber nachgedacht haben, ist es offensichtlich, dass Ihre Klasse nicht "nur eine Sache" tut, sondern eine Sammlung ist und etwas völlig anderes tut.

Lassen Sie uns das Problem nun ein wenig umgestalten: Wenn Sie Ihre Klasse in eine Klasse aufteilen, in der alles statisch ist, und eine andere, die nur eine "normale Klasse" ist, und die "normale Klasse" vergessen, wird Ihre Frage zu einer rein statischen Klasse gegen Singleton wird hier ausführlich behandelt (und wahrscheinlich ein Dutzend anderer Fragen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.