web-dev-qa-db-ger.com

Warum werden statische Variablen als böse betrachtet?

Ich bin ein Java-Programmierer, der neu in der Unternehmenswelt ist. Vor kurzem habe ich eine Anwendung entwickelt, die Groovy und Java verwendet. Der gesamte Code, den ich schrieb, verwendete eine ganze Reihe von Statiken. 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 statische Variablen ziemlich ablehnen.

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 machen müsste, wäre ich froh, die Methode statisch zu machen und stattdessen eine unkomplizierte Class.methodCall() zu verwenden der Speicher mit 10.000 Instanzen der Klasse überladen, oder?

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

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

566
Vamsi Emani

Statische Variablen repräsentieren den globalen Zustand. Das ist schwer zu verstehen und schwer zu testen: Wenn ich eine neue Instanz eines Objekts erstelle, kann ich in Tests über den neuen Zustand des Objekts nachdenken. Wenn ich Code mit statischen Variablen verwende, könnte er sich in einem beliebigen Zustand befinden - und irgendetwas könnte ihn verändern.

Ich könnte noch eine Weile weitermachen, aber das größere Konzept, über das man nachdenken sollte, ist: Je enger der Umfang von etwas, desto leichter ist es, darüber nachzudenken. Wir sind gut darin, über kleine Dinge nachzudenken, aber es ist schwer, über den Zustand eines Millionenleitungssystems nachzudenken, wenn es keine Modularität gibt. Dies gilt übrigens für alle möglichen Dinge - nicht nur für statische Variablen.

636
Jon Skeet

Es ist nicht sehr objektorientiert: Ein Grund, warum Statik von manchen Leuten als "böse" betrachtet werden könnte, ist, dass sie dem objektorientierten Paradigma zuwiderlaufen. Insbesondere verstößt es gegen das Prinzip, dass Daten in Objekten gekapselt sind (die erweitert werden können, das Ausblenden von Informationen usw.). In der Art, wie Sie sie verwenden, verwenden Statiken sie im Wesentlichen als globale Variable, um zu vermeiden, dass Probleme wie der Geltungsbereich behandelt werden. Globale Variablen sind jedoch eines der bestimmenden Merkmale des prozeduralen oder imperativen Programmierungsparadigmas und kein Merkmal von "gutem" objektorientiertem Code. Das soll nicht heißen, dass das prozedurale Paradigma schlecht ist, aber ich habe den Eindruck, dass Ihr Vorgesetzter erwartet, dass Sie "guten objektorientierten Code" schreiben und dass Sie wirklich "guten prozeduralen Code" schreiben möchten. 

Es gibt viele Gotchyas in Java, wenn Sie Statiken verwenden, die nicht immer sofort offensichtlich sind. Wenn Sie beispielsweise zwei Kopien Ihres Programms in derselben VM ausführen, werden diese den statischen Variablenwert anzeigen und sich gegenseitig mit dem Status der anderen Variablen verwechseln? Oder was passiert, wenn Sie die Klasse erweitern? Können Sie das statische Member überschreiben? Ist für Ihren VM nicht genügend Arbeitsspeicher verfügbar, weil Sie über wahnsinnige Statikzahlen verfügen und dieser Speicher nicht für andere benötigte Instanzobjekte freigegeben werden kann?

Object Lifetime: Außerdem haben Statiken eine Lebensdauer, die der gesamten Laufzeit des Programms entspricht. Das bedeutet, auch wenn Sie Ihre Klasse nicht mehr benötigen, kann der Speicher all dieser statischen Variablen nicht gesammelt werden. Wenn Sie stattdessen beispielsweise Ihre Variablen als nicht statisch festgelegt haben und in Ihrer Funktion main () eine einzelne Instanz Ihrer Klasse erstellt haben und Ihre Klasse dann 10.000 Mal aufgefordert haben, eine bestimmte Funktion 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 gesammelt und wiederverwendet werden. 

Verhindert bestimmte Wiederverwendung: Außerdem können statische Methoden nicht zum Implementieren einer Schnittstelle verwendet werden. Daher können statische Methoden die Verwendung bestimmter objektorientierter Features verhindern.

Andere Optionen: Wenn Effizienz das Hauptanliegen ist, gibt es möglicherweise andere Möglichkeiten, um das Geschwindigkeitsproblem zu lösen, als nur den Vorteil des Aufrufens zu berücksichtigen, da er normalerweise schneller ist als die Erstellung. Überlegen Sie, ob die transienten oder flüchtigen Modifikatoren überall 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 final markiert werden, um bestimmte Compiler-Optimierungen basierend auf Annahmen darüber zu ermöglichen, was diese Variablen ändern kann. Ein Instanzobjekt könnte mehrmals wiederverwendet werden, anstatt jedes Mal eine neue Instanz zu erstellen. Es gibt möglicherweise Compiler-Optimierungsschalter, die im Allgemeinen für die App aktiviert sein sollten. Möglicherweise sollte das Design so eingerichtet werden, dass die 10.000 Laufwerke Multithreading ausführen und Multiprozessorkerne nutzen können. Wenn Portablity kein Problem ist, könnte eine native Methode möglicherweise schneller sein als Ihre Statik.

Wenn Sie aus irgendeinem Grund nicht mehrere Kopien eines Objekts erstellen möchten, hat das Singleton-Entwurfsmuster Vorteile gegenüber statischen Objekten, z Das Objekt wurde ordnungsgemäß initialisiert, wenn es verwendet wird, Unterklassen, Vorteile beim Testen und Umgestalten des Codes. Ganz zu schweigen davon, wenn Sie Ihre Meinung ändern, dass nur eine Instanz eines Objekts gewünscht wird, ist es VIEL einfacher, den Code zu entfernen Duplikate von Instanzen sollten vermieden werden, als den gesamten Code Ihrer statischen Variablen für die Verwendung von Instanzvariablen umzuwandeln. Ich musste das vorher tun, es macht keinen Spaß, und Sie müssen am Ende sehr viel mehr Klassen bearbeiten, was das Risiko erhöht, neue Fehler einzuführen. Es ist viel besser, die Dinge beim ersten Mal "richtig" einzurichten. Auch wenn es so aussieht, als hätte es seine Nachteile. Für mich ist die Nacharbeit, die erforderlich ist, wenn Sie sich auf der Straße entscheiden, mehrere Kopien von etwas erforderlich, wahrscheinlich einer der zwingenden Gründe, 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 mehr gekoppelt ist, wenn Sie über viele Statiken verfügen, auf die direkt zugegriffen werden kann, und nicht auf ein Objekt, das zu tun weiß etwas "an sich". 

253
Jessica Brown

Das Böse ist ein subjektiver Begriff.

Sie haben keine Kontrolle über die Statik in Bezug auf Erstellung und Zerstörung. Sie leben auf Verlangen des Programms beim Laden und Entladen. 

Da die Statik in einem Bereich lebt, müssen alle Threads, die sie verwenden möchten, die Zugriffskontrolle durchlaufen, die Sie verwalten müssen. Dies bedeutet, dass Programme stärker miteinander gekoppelt sind und diese Änderung schwerer vorstellbar ist (wie J Skeet sagt). Dies führt zu Problemen beim Isolieren von Änderungen und beeinflusst somit die Art und Weise, wie Tests verwaltet werden.

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

90
Preet Sangha

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; So wie er jede Sprachfunktion missbrauchen würde.

Globale Zustände sind eine absolute Notwendigkeit. Wir können globale Staaten nicht vermeiden. Wir können es nicht vermeiden, über globale Staaten zu denken. - Wenn wir unsere Anwendungssemantik verstehen wollen. 

Menschen, die versuchen, sich der Weltstaaten deswegen zu entledigen, enden unvermeidlich mit einem viel komplexeren System - und die Weltstaaten sind immer noch da, unter vielen Schichten der Umwege geschickt und idiotisch verkleidet. und wir müssen immer noch über globale Zustände nachdenken, nachdem wir alle Indirektionen ausgepackt haben.

So wie die Frühlingsmenschen, die verschwenderisch globale Zustände in XML deklarieren und irgendwie denken, es sei überlegen.

@ Jon Skeet if I create a new instance of an object Sie haben jetzt zwei Dinge zu begründen - den Zustand innerhalb des Objekts und den Zustand der Umgebung, in der sich das Objekt befindet. 

55
irreputable

Es gibt zwei Hauptprobleme mit statischen Variablen:

  • Threadsicherheit - statische Ressourcen sind definitionsgemäß nicht threadsicher
  • Code Implicity - Sie wissen nicht, wann eine statische Variable instanziiert wird und ob sie vor einer anderen statischen Variablen instanziiert wird
30
sternr

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 „final“ ist kein freier Pass, da ein veränderliches statisches finales Objekt genauso gefährlich sein kann.

Ich würde schätzen, dass ungefähr 85% der Zeit, in der ich eine "statische" Situation ohne ein "Finale" sehe, falsch ist. Oft werde ich seltsame Problemumgehungen finden, um diese Probleme zu maskieren oder zu verbergen.

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

Die Verwendung von Statik kann sehr subtile Fehler verursachen, die den Ingenieuren viele Tage lang Schmerzen bereiten. Ich weiß, weil ich diese Fehler sowohl erstellt als auch gejagt habe.

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

Warum keine Statik verwenden?

Es gibt viele Probleme mit der Statik, darunter das Schreiben und Ausführen von Tests sowie subtile Fehler, die nicht sofort offensichtlich sind.

Code, der sich auf statische Objekte stützt, kann nicht einfach auf Einheit getestet werden, und Statik kann nicht so leicht verspottet werden (normalerweise).

Wenn Sie Statik verwenden, ist es nicht möglich, die Implementierung der Klasse auszutauschen, um Komponenten höherer Ebene zu testen. Stellen Sie sich beispielsweise eine statische CustomerDAO vor, die die von der Datenbank geladenen Customer-Objekte zurückgibt. Jetzt habe ich eine Klasse CustomerFilter, die auf einige Customer-Objekte zugreifen muss. Wenn CustomerDAO statisch ist, kann ich keinen Test für CustomerFilter schreiben, ohne zuerst meine Datenbank zu initialisieren und nützliche Informationen aufzufüllen.

Die Bestückung und Initialisierung der Datenbank dauert sehr lange. Meiner Erfahrung nach ändert sich Ihr DB-Initialisierungs-Framework mit der Zeit, was bedeutet, dass Daten sich verändern und Tests möglicherweise brechen. IE, stellen Sie sich vor, Kunde 1 war früher ein VIP, aber das DB-Initialisierungs-Framework hat sich geändert, und jetzt ist Kunde 1 kein VIP mehr, aber Ihr Test war hartcodiert, um Kunde 1 zu laden.

Ein besserer Ansatz besteht darin, ein CustomerDAO zu instantiieren und bei seiner Erstellung in den CustomerFilter zu übergeben. (Ein noch besserer Ansatz wäre die Verwendung von Spring oder eines anderen Inversion of Control-Frameworks).

Wenn Sie dies getan haben, können Sie schnell einen alternativen DAO in Ihrem CustomerFilterTest simulieren oder ausschalten, um mehr Kontrolle über den Test zu haben.

Ohne den statischen DAO ist der Test schneller (keine db-Initialisierung) und zuverlässiger (da er nicht fehlschlägt, wenn sich der db-Initialisierungscode ändert). In diesem Fall sollte beispielsweise sichergestellt werden, dass Kunde 1 ein VIP ist und bleibt, was den Test angeht.

Tests ausführen

Statik verursacht ein echtes Problem, wenn Sie mehrere Komponententests zusammen ausführen (z. B. mit Ihrem Continuous Integration-Server). Stellen Sie sich eine statische Karte von Netzwerk-Socket-Objekten vor, die von Test zu Test offen bleibt. Beim ersten Test wird möglicherweise ein Socket an Port 8080 geöffnet, Sie haben jedoch 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 für die Sammlung von Müll in Frage kommen, wodurch ein Speicherverlust verursacht wird.

Dies ist ein übermäßig verallgemeinertes Beispiel, aber in großen Systemen tritt dieses Problem immer auf. Die Benutzer denken nicht daran, dass Komponententests ihre Software wiederholt in derselben JVM starten und stoppen. Dies ist jedoch ein guter Test für Ihr Softwaredesign. Wenn Sie Bestrebungen nach hoher Verfügbarkeit haben, müssen Sie dies beachten.

Diese Probleme treten häufig bei Framework-Objekten auf, z. B. beim DB-Zugriff, beim Caching, beim Messaging und beim Protokollieren von Schichten. Wenn Sie Java EE oder einige der besten Frameworks verwenden, wird dies wahrscheinlich für Sie erledigt. Wenn Sie jedoch wie ich mit einem Altsystem zu tun haben, verfügen Sie möglicherweise über viele benutzerdefinierte Frameworks, um auf diese Ebenen zuzugreifen.

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

Sogar Nicht-Framework-Komponenten unterliegen diesem Problem. Stellen Sie sich eine statische Karte mit dem Namen OpenOrders vor. Sie schreiben einen Test, der einige offene Aufträge erstellt, und prüft, ob alle im richtigen Status sind. Dann endet der Test. Ein anderer Entwickler schreibt einen zweiten Test, der die benötigten Bestellungen in die OpenOrders-Map einfügt und dann die Anzahl der Bestellungen als richtig ansieht. Wenn Sie diese Tests einzeln ausführen, werden beide Tests bestanden. Wenn sie jedoch zusammen in einer Suite ausgeführt werden, schlagen sie fehl.

Schlimmer noch, der Fehler kann in der Reihenfolge der Tests basieren.

In diesem Fall vermeiden Sie durch das Vermeiden von Statik das Risiko, dass Daten über Testinstanzen hinweg bestehen bleiben, wodurch eine höhere Zuverlässigkeit der Tests gewährleistet wird. Subtile Fehler .

Wenn Sie in einer Hochverfügbarkeitsumgebung arbeiten oder an Stellen, an denen Threads gestartet und gestoppt werden, kann das gleiche Problem wie bei Einheitstestsuiten zutreffen, wenn Ihr Code auch 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 bei jedem Start des Threads eine neue Instanz des Objekts (mit einer möglicherweise neuen Konfiguration) erstellt, und Sie vermeiden, dass Daten von einer Instanz des Threads in die nächste Instanz übergehen.

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", und wenn er gestartet wird, füllt er eine statische String-Sammlung mit einer Liste von E-Mail-Adressen auf und beginnt dann, jede der Adressen per E-Mail zu senden. Nehmen wir an, der Thread wurde unterbrochen oder abgebrochen, so dass Ihr Framework mit hoher Verfügbarkeit den Thread neu startet. Wenn der Thread dann gestartet wird, wird die Liste der Kunden erneut geladen. Da die Sammlung jedoch statisch ist, wird möglicherweise die Liste der E-Mail-Adressen der vorherigen Sammlung beibehalten. Einige Kunden erhalten möglicherweise doppelte E-Mails.

Nebenbei: Statisches Finale .

Die Verwendung von "static final" ist praktisch das Java-Äquivalent einer C # -Definition, obwohl es technische Unterschiede gibt. Eine C/C++ - # -Definition wird vor der Kompilierung vom Vorprozessor aus dem Code ausgelagert. Ein "statisches Java-Finale" wird den auf dem Stack residenten Speicher beenden. Auf diese Weise ähnelt es einer "statischen const" -Variablen in C++ eher als einer # Definition.

Zusammenfassung .

Ich hoffe, das hilft, ein paar grundlegende Gründe zu erklären, 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 einem großen Bestand an altem Code arbeiten, können diese sehr viel häufiger werden.

I hope this helps explain a few basic reasons why statics are problematic up. If you are using a modern Java framework like Java EE or Spring, etc, you may not encounter many of these situations, but if you are working with a large body of legacy code, they can become much more frequent.

27
JBCP

Da hat niemand * es erwähnt: Parallelität. Statische Variablen können Sie überraschen, wenn Sie mehrere Threads lesen und in die statische Variable schreiben. Dies ist bei Webanwendungen (z. B. ASP.NET) üblich und kann einige ziemlich lästige Fehler verursachen. Wenn Sie beispielsweise über eine statische Variable verfügen, die von einer Seite aktualisiert wird, und die Seite "fast gleichzeitig" von zwei Personen angefordert wird, kann ein Benutzer das vom anderen Benutzer erwartete Ergebnis erhalten oder schlechter.

statiken reduzieren die Abhängigkeiten zu den anderen Teilen des Codes. Sie können als perfekte Staatsinhaber fungieren

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

* Eigentlich hat Preet Sangha es erwähnt.

14
Justin M. Keyes

wenn ich 10.000 Aufrufe an eine Funktion innerhalb einer Klasse machen müsste, wäre ich Ich freue mich, die Methode statisch zu machen und eine einfache Methode zu verwenden class.methodCall () darauf, anstatt den Speicher mit 10.000 zu überladen Instanzen der Klasse, richtig?

Sie müssen die Notwendigkeit, Daten in ein Objekt einzukapseln, mit einem Status abwägen, anstatt das Ergebnis einer Funktion anhand einiger Daten berechnen zu müssen.

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

So auch die Kapselung. In großen Anwendungen neigen Statiken dazu, Spaghetti-Code zu erzeugen und lassen sich nicht leicht umgestalten oder testen.

Die anderen Antworten geben auch gute Gründe gegen den übermäßigen Gebrauch von Statik an.

13

Statische Variablen werden im Allgemeinen als schlecht angesehen, da sie einen globalen Zustand darstellen und daher viel schwieriger zu verstehen sind. Sie brechen insbesondere die Annahmen der objektorientierten Programmierung. Bei der objektorientierten Programmierung hat jedes Objekt seinen eigenen Zustand, der durch Instanzvariablen (nicht statisch) dargestellt wird. Statische Variablen repräsentieren den Zustand über alle Instanzen hinweg, deren Einheitstest viel schwieriger sein kann. Dies liegt vor allem daran, dass es schwieriger ist, Änderungen an statischen Variablen für einen einzelnen Test zu isolieren.

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

12
Jack Edmonds

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

Vorteile:

  1. Global zugänglich, d. H. Nicht an eine bestimmte Objektinstanz gebunden.
  2. Eine Instanz pro JVM.
  3. Zugriff über Klassenname möglich (Kein Objekt erforderlich).
  4. Enthält einen einzigen Wert, der für alle Instanzen gilt.
  5. Laden Sie sich beim Start der JVM hoch und stirbt ab, wenn die JVM heruntergefahren wird.
  6. Sie ändern den Zustand des Objekts nicht.

Nachteile:

  1. Statische Member sind immer Teil des Arbeitsspeichers, unabhängig davon, ob sie verwendet werden oder nicht.
  2. Sie können die Erstellung und Zerstörung statischer Variablen nicht steuern. Sie wurden beim Laden des Programms erstellt und beim Entladen des Programms (oder beim Herunterfahren der JVM) zerstört. 
  3. Sie können den Statikthread mithilfe von synchronize sicherer 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” wissen, bevor Sie es verwenden.
  6. Sie können statische Methoden nicht überschreiben.
  7. Die Serialisierung funktioniert nicht gut mit ihnen.
  8. Sie beteiligen sich nicht am Laufzeitpolymorphismus.
  9. Wenn eine große Anzahl statischer Variablen/Methoden verwendet wird, gibt es ein Speicherproblem (in gewissem Umfang, aber nicht viel, denke ich). Weil sie nicht bis zum Ende des Programms entsorgt werden. 
  10. Statische Methoden sind auch schwer zu testen.
10
Virtual

Meiner Meinung nach geht es kaum um Leistung, es geht um Design. Ich halte die Verwendung statischer Methoden nicht für falsch, da sie statische Variablen verwendet. 

Es geht einfach darum, wie man die Logik isoliert und einen guten Platz einnimmt. Manchmal rechtfertigt dies die Verwendung statischer Methoden, von denen Java.lang.Math ein gutes Beispiel ist. Ich denke, wenn Sie die meisten Ihrer Klassen XxxUtil oder Xxxhelper nennen, sollten Sie Ihr Design besser überdenken.

9
M Platvoet

Ich habe gerade einige der in den Antworten genannten Punkte zusammengefasst. Wenn Sie etwas falsch finden, korrigieren Sie es bitte.

Skalierung: Wir haben genau eine Instanz einer statischen Variablen pro JVM. Nehmen wir an, wir entwickeln ein Bibliotheksverwaltungssystem, und wir haben beschlossen, dem Namen des Buches eine statische Variable zu geben, 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 uns befassen?

Thread-Safety: Bei Verwendung in einer Umgebung mit mehreren Threads müssen sowohl die Instanzvariable als auch die statische Variable gesteuert werden. Im Fall einer Instanzvariablen muss diese jedoch nur geschützt werden, wenn sie explizit von Threads gemeinsam genutzt wird. Bei einer statischen Variablen wird sie jedoch immer von allen Threads des Prozesses gemeinsam genutzt. 

Testing: Obwohl testbares Design nicht gleich gutem Design entspricht, werden wir selten ein gutes Design beobachten, das nicht testbar ist. Da statische Variablen den globalen Zustand repräsentieren, ist es sehr schwierig, sie zu testen.

Begründungen über den Zustand: Wenn ich eine neue Instanz einer Klasse erstelle, können wir über den Zustand dieser Instanz nachdenken, aber wenn sie statische Variablen enthält, kann sie sich in einem beliebigen Zustand befinden. Warum? Es ist möglich, dass die statische Variable von einer anderen Instanz geändert wurde, da die statische Variable von allen Instanzen gemeinsam genutzt wird. 

Serialisierung: Die Serialisierung funktioniert auch nicht gut mit ihnen.

Erstellung und Zerstörung: Die Erstellung 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 schlecht für die Speicherverwaltung sind und die Initialisierungszeit beim Start summieren.

Aber was ist, wenn wir sie wirklich brauchen?

Aber manchmal brauchen wir sie wirklich. Wenn wir wirklich das Bedürfnis nach vielen statischen Variablen empfinden, die in der gesamten Anwendung gemeinsam genutzt werden, können Sie das Singleton Design-Muster verwenden, das alle diese Variablen enthält. Oder wir können ein Objekt erstellen, das diese statische Variable hat und herumgereicht werden kann.

Wenn die statische Variable als final markiert ist, wird sie zu einer Konstanten, und der einmal zugewiesene Wert kann nicht geändert werden. Dies bedeutet, dass es uns vor allen Problemen retten wird, denen wir aufgrund seiner Wandlungsfähigkeit gegenüberstehen.

6
i_am_zero

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 bei globalen Zuständen ist, dass das, was in einem einfacheren Kontext als global sinnvoll erscheint, in einem praktischen Kontext etwas flexibler sein muss, und hier wird das Singleton-Muster nützlich.

6
Charles Goodwin

Es scheint mir, dass Sie nach statischen Variablen fragen, aber Sie zeigen in Ihren Beispielen auch statische Methoden auf.

Statische Variablen sind nicht böse - sie werden in den meisten Fällen als globale Variablen wie Konstanten kombiniert mit finalem Modifikator verwendet, aber wie gesagt, sie nicht überbeanspruchen.

Statische Methoden auch als Utility-Methode bezeichnet. Es ist im Allgemeinen keine schlechte Praxis, sie zu verwenden, aber das Hauptproblem ist, dass sie behindern testen könnten.

Als Beispiel für ein großartiges Java-Projekt, das viele Statiken verwendet und es richtig macht, schauen Sie sich bitte Play! Framework an. Es gibt auch Diskussion darüber in SO.

Statische Variablen/Methoden kombiniert mit statischem Import werden auch häufig in Bibliotheken verwendet, die die deklarative Programmierung in Java erleichtern, wie zum Beispiel: macht es einfach oder Hamcrest . Ohne viele statische Variablen und Methoden wäre dies nicht möglich.

Statische Variablen (und Methoden) sind also gut, verwenden Sie sie jedoch mit Bedacht!

6
cetnar

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

Für weitere Informationen lesen Sie this Danke.

6
Anuj Patel

Ein weiterer Grund: Zerbrechlichkeit.

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

Sie können dokumentieren, dass dies nicht der Fall ist, oder sich dagegen schützen (Singleton/Factory-Pattern) - aber das ist zusätzliche Arbeit und daher zusätzliche Kosten. Selbst dann, in einer großen Firma, besteht die Chance, dass jemand irgendwann versucht Verwenden Sie Ihre Klasse, ohne die Nice-Kommentare oder die Fabrik zu beachten.

Wenn Sie häufig statische Variablen verwenden, wird dies zerbrechen. Fehler sind teuer.

Zwischen einer Leistungsverbesserung von 0,0001% und der Robustheit, die von potenziell ahnungslosen Entwicklern geändert werden kann, ist in vielen Fällen Robustheit die richtige Wahl.

5
ptyx

Es gibt nichts an statischen Variablen per se. Es ist nur die Java-Syntax gebrochen. Jede Java-Klasse definiert tatsächlich zwei Strukturen - ein Einzelobjekt, das statische Variablen enthält, und eine Instanz. Beide in demselben Quellblock zu definieren, ist rein böse und führt zu einem schwer lesbaren Code. Scala hat das richtig gemacht.

4
Zdeněk Pavlas

Das Thema "Statik ist böse" ist eher ein Problem des globalen Staates. Die geeignete Zeit für eine Variable ist statisch, wenn sie nicht mehr als einen Zustand hat. IE - Tools, die für das gesamte Framework zugänglich sein sollten und immer dieselben Ergebnisse für dieselben Methodenaufrufe zurückgeben, sind niemals "böse" wie 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 niemals ändern.

Das Problem mit dem globalen Zustand ist die inhärente Inkonsistenz, die es schaffen kann. Die Dokumentation zu Komponententests befasst sich häufig mit diesem Problem, da jedes Mal, wenn ein globaler Status von mehr als mehreren nicht zusammenhängenden Objekten abgerufen wird, die Komponententests unvollständig sind und keine "Einheit" -Körnung. Wie in diesem Artikel zu globaler Zustand und Singletons erwähnt, sollten Objekt A und B nicht miteinander verwandt sein (da in einem Objekt nicht ausdrücklich auf ein anderes Objekt verwiesen wird), sollte A den Status von B nicht beeinflussen können.

Es gibt einige Ausnahmen zum globalen Verbot in gutem Code, wie z. B. die Uhr. Zeit ist global und ändert gewissermaßen den Zustand von Objekten, ohne eine kodierte Beziehung zu haben.

4
Bryan Agee

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). Wenn ich 10.000 Aufrufe an eine Funktion innerhalb einer Klasse machen müsste, würde ich gerne die Methode statisch machen und eine einfache Klasse verwenden. darauf, anstatt den Speicher mit 10.000 Instanzen der Klasse zu überladen, richtig?  

Ich verstehe, was Sie denken, aber ein einfaches Singleton-Muster wird dasselbe tun, ohne 10.000 Objekte zu instanziieren.

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)...

}
4
Cygnusx1

Meine $ .02 ist, dass einige dieser Antworten das Thema verwirren, anstatt zu sagen "Statik sind schlecht". Ich denke, es ist besser, über Scoping und Instanzen zu sprechen.

Was ich sagen würde ist, dass eine statische Variable eine "Klassenvariable" ist - sie repräsentiert einen Wert, der für alle Instanzen dieser Klasse verwendet wird. Normalerweise sollte es auch auf diese Weise (geschützt oder privat für die Klasse und ihre Instanzen) gelten.

Wenn Sie vorhaben, das Verhalten auf Klassenebene umzusetzen und anderen Code bereitzustellen, ist ein Singleton möglicherweise eine bessere Lösung, um Änderungen in der Zukunft zu unterstützen (wie @Jessica vorschlug). Dies liegt daran, dass Sie Schnittstellen auf Instanz-/Singleton-Ebene auf eine Weise verwenden können, die Sie nicht auf Klassenebene verwenden können - insbesondere die Vererbung.

Einige Gedanken dazu, warum ich denke, dass einige der Aspekte in anderen Antworten nicht die Kernfrage darstellen ...

Statik ist nicht "global". In Java wird das Scoping getrennt von statisch/Instanz gesteuert. 

Parallelität ist für Statik nicht weniger gefährlich als Instanzmethoden. Es ist immer noch ein Zustand, der geschützt werden muss. Sicher können Sie 1000 Instanzen mit jeweils einer Instanzvariablen und nur einer statischen Variablen haben, aber wenn der Code, auf den zugegriffen wird, nicht fadensicher geschrieben wurde, sind Sie immer noch in der Luft - es kann nur etwas länger dauern, bis Sie dies realisieren .

Der Lebenszyklus zu managen ist ein interessantes Argument, aber ich denke, es ist weniger wichtig. Ich kann nicht verstehen, warum es schwieriger ist, ein Paar Klassenmethoden wie init ()/clear () zu verwalten, als das Erstellen und Zerstören einer Einzelinstanz. In der Tat könnte man sagen, ein Singleton ist aufgrund der GC etwas komplizierter.

In Bezug auf Smalltalk haben viele ihrer Dialekte Klassenvariablen, aber in Smalltalk-Klassen handelt es sich tatsächlich um Instanzen von Metaclass, also um Variablen der Metaclass-Instanz. Trotzdem würde ich dieselbe Faustregel anwenden. Wenn sie für mehrere Instanzen gemeinsam genutzt werden, dann ok. Wenn sie öffentliche Funktionen unterstützen, sollten Sie sich ein Singleton ansehen. Seufz, ich vermisse wirklich Smalltalk ....

4
studgeek

In Ihrem Beitrag gibt es zwei Hauptfragen.

Erstens über statische Variablen ..__ Statische Variablen sind völlig unnötig und ihre Verwendung kann leicht vermieden werden. In OOP -Sprachen im Allgemeinen und insbesondere in Java werden Funktionsparameter durch Verweise übergeben. Wenn Sie also ein Objekt an eine Funktion übergeben, übergeben Sie einen Zeiger auf das Objekt, sodass Sie dies nicht tun müssen Definieren Sie statische Variablen, da Sie einen Zeiger auf das Objekt an jeden Bereich übergeben können, der diese Informationen benötigt. Auch wenn dies impliziert, dass Sie Ihr Gedächtnis mit Zeigern füllen, ist dies nicht unbedingt eine schlechte Leistung, da die Systeme zum Speichern von Speichersystemen für diesen Vorgang optimiert sind und die Seiten, auf die die Zeiger verweisen, die Sie an das neue übergeben haben, im Speicher behalten Umfang; Die Verwendung statischer Variablen kann dazu führen, dass das System die Speicherseite lädt, wo sie gespeichert werden, wenn auf sie zugegriffen werden muss (dies geschieht, wenn die Seite längere Zeit nicht aufgerufen wurde). Es empfiehlt sich, all diese statischen Daten in ein paar "Konfigurationsclases" zusammenzufassen. Dadurch wird sichergestellt, dass das System alles auf derselben Speicherseite ablegt.

Zweitens über statische Methoden ..__ Statische Methoden sind zwar nicht so schlecht, aber sie können 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, aber beim Aufruf der nicht statischen Form ist dies effizienter da nur zwei Referenzen (eine für jedes Objekt) gegenüber den drei Referenzen gelö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 Math-Klasse anschauen, können wir viele mathematische Funktionen finden, die als statische Methoden definiert sind. Dies ist wirklich effizienter, als alle diese Methoden in die Klasse zu setzen, die die Zahlen definiert, da die meisten von ihnen selten verwendet werden. Wenn Sie alle in die Zahlenklasse aufnehmen, wird die Klasse sehr komplex und verbraucht viele Ressourcen unnötig.

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

PS: Sorry für mein Englisch.

3
jrodriguez

a) Gründe für Programme.

Wenn Sie ein kleines bis mittelgroßes Programm haben, auf das auf die statische Variable Global.foo zugegriffen wird, kommt der Aufruf normalerweise von nirgendwo - es gibt keinen Pfad und daher keine Zeitleiste, wie die Variable an den Ort und an den Ort gelangt wird eingesetzt. Woher weiß ich jetzt, wer den tatsächlichen Wert eingestellt hat? Woher weiß ich, was passiert, wenn ich es jetzt ä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 den Code gerade geschrieben haben, ist das Problem nicht sichtbar, aber wenn Sie versuchen, Fremdcode zu verstehen, werden Sie es 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. Häufig sehen Sie keine Verwendungen vor, bei denen mehrere Instanzen Ihres Programms nützlich sind, aber wenn sich das Programm weiterentwickelt oder wenn es für andere nützlich ist, kann dies zu Situationen führen, in denen mehrere Instanzen Ihres Programms gestartet werden sollen . 

Nur mehr oder weniger nutzloser Code, der von vielen Menschen über längere Zeit nicht intensiv verwendet wird, könnte gut zu statischen Variablen passen. 

3
user unknown

alles (kann :) seinen Zweck haben, wenn Sie eine Reihe von Threads haben, die share/cache data und auch alle zugänglichen Speicher benötigen (damit Sie nicht in Kontexte innerhalb einer JVM aufteilen), ist die Statik am besten Wahl

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

3
tomasb

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

2
blockhead

Statische Variablen sind weder gut noch böse. Sie repräsentieren Attribute, 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 für den Wert.

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

2
Andres

Es gibt viele gute Antworten, die dazu beitragen, 

Erinnerung: Statische Variablen sind lebendig, solange der Klassenlader [im Allgemeinen bis VM] stirbt. Dies gilt jedoch nur für Massenobjekte/Referenzen, die als statisch gespeichert sind.

Modularisierung: Berücksichtigen Sie Konzepte wie IOC, DependencyInjection, Proxy usw. Alle sind gegen strikte Kopplungs-/statische Implementierungen.

Andere Con's: Threadsicherheit, Testbarkeit

Aus meiner Sicht sollte static nur aus read only data oder Variablen bestehen, die durch Konvention erstellt wurden.

Zum Beispiel haben wir eine UI von einem Projekt, und wir haben 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 in App init tun, ist das Überprüfen dieser Liste auf Updates und das Abrufen dieser Liste von API (falls erforderlich). Wir sind uns daher einig, dass diese Daten in der App "immer" vorhanden sind. Es handelt sich praktisch um schreibgeschützte Daten, sodass wir uns nicht um den Zustand kümmern müssen. Wenn wir über diesen Fall nachdenken, möchten wir nicht viele Fälle dieser Daten haben - dieser Fall ist der perfekte Kandidat für statisch.

0
qiAlex

Wenn Sie über eine Anwendung mit vielen Benutzern verfügen und ein statisches Formular definieren, werden alle Benutzer auch alle anderen Formulare anderer Benutzer ändern.

0
seinta

Ich denke, die übermäßige Verwendung globaler Variablen mit statischen Schlüsselwörtern führt an einer bestimmten Stelle in der Anwendung zu Speicherverlusten

0
Rahul Anand