Als ich erfuhr, dass die Klasse java.lang.String
in Java als endgültig deklariert ist, habe ich mich gefragt, warum das so ist. Ich habe damals keine Antwort gefunden, aber diesen Beitrag: Wie erstelle ich ein Replikat der String-Klasse in Java? erinnerte mich an meine Anfrage.
Sicher, String bietet alle Funktionen, die ich jemals benötigt habe, und ich habe nie an eine Operation gedacht, die eine Erweiterung der Klasse String erfordern würde, aber Sie werden trotzdem nie wissen, was jemand benötigt!
Weiß jemand, was die Absicht der Designer war, als sie beschlossen, es endgültig zu machen?
Antworten:
Es ist sehr nützlich, Zeichenfolgen als unveränderliche Objekte zu implementieren . Sie sollten über Unveränderlichkeit lesen , um mehr darüber zu verstehen.
Ein Vorteil von unveränderlichen Objekten ist das
(von hier ).
Wenn String nicht endgültig wäre, könnten Sie eine Unterklasse erstellen und zwei Strings haben, die sich ähnlich sehen, wenn sie als Strings angesehen werden, aber tatsächlich unterschiedlich sind.
quelle
Dies ist ein schöner Artikel , der zwei Gründe umreißt, die bereits in den obigen Antworten erwähnt wurden:
Und dies ist wahrscheinlich der ausführlichste Kommentar in diesem Artikel. Dies hat mit dem String-Pool in Java und Sicherheitsproblemen zu tun. Es geht darum, wie man entscheidet, was in den String-Pool geht. Angenommen, beide Zeichenfolgen sind gleich, wenn ihre Zeichenfolge gleich ist, dann haben wir eine Race-Bedingung, wer zuerst dort ankommt und damit Sicherheitsprobleme. Wenn nicht, enthält der Zeichenfolgenpool redundante Zeichenfolgen, wodurch der Vorteil verloren geht, dass er überhaupt vorhanden ist. Lesen Sie es einfach selbst vor, oder?
Das Erweitern des Strings würde mit Gleichen und Praktikanten Chaos anrichten. JavaDoc sagt gleich:
Vorausgesetzt, es
java.lang.String
war nicht endgültig,SafeString
könnte a gleich a seinString
und umgekehrt; weil sie die gleiche Folge von Zeichen darstellen würden.Was würde passieren, wenn Sie sich
intern
bei a bewerbenSafeString
würden - würde dasSafeString
in den String-Pool der JVM gehen? DieClassLoader
und alle Objekte, auf dieSafeString
die Referenzen verweisen, werden dann für die Lebensdauer der JVM an Ort und Stelle gesperrt. Sie würden eine Rennbedingung darüber erhalten, wer als erster eine Folge von Charakteren internieren könnte - vielleichtSafeString
würden Sie gewinnen, vielleicht eineString
oder vielleicht eineSafeString
von einem anderen Klassenlader geladene (also eine andere Klasse).Wenn Sie das Rennen in den Pool gewinnen würden, wäre dies ein echter Singleton und die Leute könnten durch Reflexion und auf Ihre gesamte Umgebung (Sandbox) zugreifen
secretKey.intern().getClass().getClassLoader()
.Oder die JVM könnte dieses Loch blockieren, indem sie sicherstellt, dass nur konkrete String-Objekte (und keine Unterklassen) zum Pool hinzugefügt wurden.
Wenn equals so implementiert wurde, dass
SafeString
! =String
ThenSafeString.intern
! =String.intern
UndSafeString
zum Pool hinzugefügt werden müsste. Der Pool würde dann zu einem Pool von<Class, String>
statt<String>
und alles, was Sie brauchen, um den Pool zu betreten, wäre ein frischer Klassenlader.quelle
Der absolut wichtigste Grund dafür, dass String unveränderlich oder endgültig ist, ist, dass er vom Klassenlademechanismus verwendet wird und daher tiefgreifende und grundlegende Sicherheitsaspekte aufweist.
Wäre String veränderlich oder nicht endgültig gewesen, hätte eine Anforderung zum Laden von "java.io.Writer" in "mil.vogoon.DiskErasingWriter" geändert werden können.
Referenz: Warum String in Java unveränderlich ist
quelle
String
ist eine sehr wichtige Klasse in Java. Viele Dinge hängen davon ab, dass sie auf eine bestimmte Weise funktioniert, zum Beispiel unveränderlich.Durch das Erstellen der Klasse
final
werden Unterklassen verhindert, die diese Annahmen verletzen könnten.Beachten Sie, dass Sie auch jetzt, wenn Sie Reflection verwenden, Strings unterbrechen können (ändern Sie deren Wert oder Hashcode). Die Reflexion kann mit einem Sicherheitsmanager gestoppt werden. Wenn
String
nichtfinal
, könnte es jeder tun.Andere Klassen, die nicht deklariert sind,
final
ermöglichen es Ihnen, etwasList
fehlerhafte Unterklassen zu definieren (Sie könnten beispielsweise eine haben , die zur falschen Position hinzufügt), aber zumindest hängt die JVM nicht von denen für ihre Kernoperationen ab.quelle
final
auf eine Klasse garantiert keine Unveränderlichkeit. Es garantiert nur, dass die Invarianten einer Klasse (von denen eine Unveränderlichkeit sein kann) nicht von einer Unterklasse geändert werden können.Wie Bruno sagte, geht es um Unveränderlichkeit. Es geht nicht nur um Strings, sondern auch um Wrapper, z. B. Double, Integer, Character usw. Dafür gibt es viele Gründe:
Grundsätzlich können Sie als Programmierer sicher sein, dass Ihre Zeichenfolge niemals geändert wird. Wenn Sie wissen, wie es funktioniert, kann es auch das Speichermanagement verbessern. Versuchen Sie, zwei identische Zeichenfolgen nacheinander zu erstellen, z. B. "Hallo". Wenn Sie debuggen, werden Sie feststellen, dass sie identische IDs haben, was bedeutet, dass sie genau DIE GLEICHEN Objekte sind. Dies liegt an der Tatsache, dass Sie es mit Java tun können. Dies wäre nicht möglich, wenn die Saiten muttable wären. Sie können das gleiche haben, was ich usw. hätte, weil sie sich nie ändern werden. Wenn Sie sich also jemals dazu entschließen, 1.000.000 Zeichenfolgen "Hallo" zu erstellen, würden Sie wirklich 1.000.000 Zeiger auf "Hallo" erstellen. Wenn Sie eine Funktion für eine Zeichenfolge oder Wrapper aus diesem Grund verwenden, wird auch ein anderes Objekt erstellt (sehen Sie sich erneut die Objekt-ID an - sie ändert sich).
Ein zusätzliches Finale in Java bedeutet nicht unbedingt , dass sich das Objekt nicht ändern kann (es unterscheidet sich beispielsweise von C ++). Dies bedeutet, dass sich die Adresse, auf die sie verweist, nicht ändern kann, Sie jedoch die Eigenschaften und / oder Attribute ändern können. Daher kann es in einigen Fällen sehr wichtig sein, den Unterschied zwischen Unveränderlichkeit und Endgültigkeit zu verstehen.
HTH
Verweise:
quelle
Möglicherweise wurde die Implementierung vereinfacht. Wenn Sie eine Klasse entwerfen, die von Benutzern der Klasse vererbt werden kann, müssen Sie eine ganze Reihe neuer Anwendungsfälle in Ihr Design einbeziehen. Was passiert, wenn sie dies oder jenes mit X-geschütztem Feld tun? Wenn sie es endgültig machen, können sie sich darauf konzentrieren, dass die öffentliche Benutzeroberfläche ordnungsgemäß funktioniert, und sicherstellen, dass sie solide ist.
quelle
Mit vielen guten Punkten, die bereits erwähnt wurden, möchte ich noch einen hinzufügen. Einer der Gründe, warum String in Java unveränderlich ist, besteht darin, String zu erlauben , seinen Hashcode zwischenzuspeichern , und String in Java seinen Hashcode zwischenzuspeichern und nicht jeden zu berechnen Mal rufen wir die Hashcode-Methode von String auf , was es sehr schnell macht, als Hashmap-Schlüssel in Hashmap in Java verwendet zu werden.
Kurz gesagt, da String unveränderlich ist, kann niemand seinen Inhalt nach seiner Erstellung ändern, was garantiert, dass der Hashcode von String bei mehreren Aufrufen gleich ist.
Wenn Sie sehen, dass
String
Klasse hat, wird als deklariertund
hashcode()
Funktion ist wie folgt -Wenn es sich bereits um einen Computer handelt, geben Sie einfach den Wert zurück.
quelle
Um sicherzustellen, dass wir keine bessere Implementierung erhalten. Es sollte natürlich eine Schnittstelle gewesen sein.
Ah, ich bekomme mehr ahnungslose Abstimmungen. Die Antwort ist absolut ernst. Ich musste mich mehrmals um die blöde String-Implementierung herum programmieren, was zu erheblichen Leistungs- und Produktivitätsverlusten führte
quelle
Abgesehen von den offensichtlichen Gründen, die in anderen Antworten vorgeschlagen wurden, könnte ein Gedanke, die String-Klasse endgültig zu machen, auch mit dem Leistungsaufwand für virtuelle Methoden zusammenhängen. Denken Sie daran, dass String eine schwere Klasse ist. Dies bedeutet, dass dies keine Unterimplementierung bedeutet und dass kein Overhead für Indirektionsaufrufe erforderlich ist. Natürlich haben wir jetzt Dinge wie Virtual Invoke und andere, die diese Art der Optimierung immer für Sie durchführen.
quelle
Zusätzlich zu den in anderen Antworten genannten Gründen (Sicherheit, Unveränderlichkeit, Leistung) sollte beachtet werden, dass
String
eine spezielle Sprachunterstützung vorliegt. Sie könnenString
Literale schreiben und es gibt Unterstützung für die+
Operator wird unterstützt. Das Zulassen von Unterklassen für ProgrammiererString
würde Hacks fördern wie:quelle
Nun, ich habe einen anderen Gedanken, ich bin nicht sicher, ob ich richtig bin oder nicht, aber in Java ist String das einzige Objekt, das auch als primitiver Datentyp behandelt werden kann. Ich meine, wir können ein String-Objekt als String name = "java erstellen " . Wie bei anderen primitiven Datentypen, die nach Wert kopiert und nicht nach Referenz kopiert werden, wird erwartet, dass String dasselbe Verhalten aufweist, weshalb String endgültig ist. Das habe ich mir gedacht. Bitte ignorieren Sie, wenn es völlig unlogisch ist.
quelle
Die Endgültigkeit der Saiten verteidigt sie auch als Standard. In C ++ können Sie Unterklassen von Zeichenfolgen erstellen, sodass jeder Programmiershop eine eigene Version von Zeichenfolgen haben kann. Dies würde zu einem Mangel an einem starken Standard führen.
quelle
Angenommen, Sie haben eine
Employee
Klasse mit einer Methodegreet
. Wenn diegreet
Methode aufgerufen wird, wird sie einfach gedrucktHello everyone!
. Das ist also das erwartete Verhalten dergreet
MethodeLassen Sie nun die
GrumpyEmployee
UnterklasseEmployee
und überschreiben Sie diegreet
Methode wie unten gezeigt.Schauen Sie sich nun im folgenden Code die
sayHello
Methode an. Es nimmt dieEmployee
Instanz als Parameter und ruft die greet-Methode auf, in der Hoffnung, dass sie sagen würde.Hello everyone!
Aber was wir bekommen, istGet lost!
. Diese Verhaltensänderung ist auf zurückzuführenEmployee grumpyEmployee = new GrumpyEmployee();
Diese Situation kann vermieden werden, wenn der
Employee
Unterricht gemacht wurdefinal
. Jetzt liegt es an Ihrer Vorstellungskraft, wie viel Chaos ein frecher Programmierer verursachen könnte, wennString
Class nicht als deklariert würdefinal
.quelle
Weiß JVM, was unveränderlich ist? Die Antwort lautet Nein. Der Konstantenpool enthält alle unveränderlichen Felder, aber alle unveränderlichen Felder / Objekte werden nicht nur im Konstantenpool gespeichert. Nur wir implementieren es so, dass es Unveränderlichkeit und seine Eigenschaften erreicht. CustomString könnte implementiert werden, ohne es mit MarkerInterface endgültig zu machen, was ein spezielles Java-Verhalten für das Pooling bieten würde. Die Funktion wird noch erwartet!
quelle
Die meisten Antworten beziehen sich auf die Unveränderlichkeit - warum ein Objekt vom Typ String nicht an Ort und Stelle aktualisiert werden kann. Hier gibt es viele gute Diskussionen, und die Java-Community würde gut daran tun, Unveränderlichkeit als Prinzip zu übernehmen. (Ich halte nicht den Atem an.)
Die Frage des OP ist jedoch, warum es endgültig ist - warum es nicht erweitert werden kann. Einige hier haben dies übernommen, aber ich würde dem OP zustimmen, dass es hier eine echte Lücke gibt. In anderen Sprachen können Entwickler neue Nominaltypen für einen Typ erstellen. Zum Beispiel kann ich in Haskell die folgenden neuen Typen erstellen, die zur Laufzeit mit Text identisch sind, aber beim Kompilieren Bindungssicherheit bieten.
Daher würde ich den folgenden Vorschlag als Erweiterung der Java-Sprache vorschlagen:
(Oder vielleicht könnten wir anfangen, uns von Java zu trennen)
quelle
Wenn Sie eine Zeichenfolge einmal erstellen Es wird berücksichtigt, dass es sich um ein Objekt handelt, wenn Sie dies ändern möchten. Es ist nicht möglich, dass ein neues Objekt erstellt wird.
quelle