JavaRush /Java-Blog /Random-DE /Strings in Java (Klasse java.lang.String)
Viacheslav
Level 3

Strings in Java (Klasse java.lang.String)

Veröffentlicht in der Gruppe Random-DE

Einführung

Der Weg eines Programmierers ist ein komplexer und langer Prozess. Und in den meisten Fällen beginnt es mit einem Programm, das Hello World auf dem Bildschirm anzeigt. Java ist keine Ausnahme (siehe Lektion: Die Anwendung „Hello World!“ ). Wie wir sehen können, wird die Nachricht mit ausgegeben. System.out.println("Hello World!"); Wenn Sie sich die Java-API ansehen, verwendet die System.out.println- Methode String als Eingabeparameter . Diese Art von Daten wird besprochen.

String als Folge von Zeichen

Eigentlich ist String aus dem Englischen übersetzt ein String. Das ist richtig, der String-Typ repräsentiert eine Textzeichenfolge. Was ist eine Textzeichenfolge? Eine Textzeichenfolge ist eine Art geordnete Folge aufeinander folgender Zeichen. Das Symbol ist char. Reihenfolge – Reihenfolge. Also ja, absolut richtig, String ist eine Implementierung von java.lang.CharSequence. Und wenn Sie einen Blick in die String-Klasse selbst werfen, sehen Sie darin nichts weiter als ein Array von Zeichen: private final char value[]; Sie hat java.lang.CharSequenceeinen ziemlich einfachen Vertrag:
Strings in Java (Klasse java.lang.String) – 1
Wir haben eine Methode zum Abrufen der Anzahl von Elementen, zum Abrufen eines bestimmten Elements und zum Abrufen einer Menge von Elementen + die toString-Methode selbst, die dies zurückgibt.) Es ist interessanter, die Methoden zu verstehen, die uns in Java 8 zur Verfügung standen, und das ist : chars()und codePoints() erinnern Sie sich aus dem Tutorial von Oracle „ Primitive Data“-Typen , dass char ist single 16-bit Unicode character. Das heißt, char ist im Wesentlichen nur ein Typ, der halb so groß ist wie ein int (32 Bit), der Zahlen von 0 bis 65535 darstellt (siehe Dezimalwerte). in der ASCII-Tabelle ). Das heißt, wenn wir möchten, können wir char als int darstellen. Und Java 8 machte sich dies zunutze. Ab Version 8 von Java gibt es IntStream – einen Stream für die Arbeit mit primitiven Ints. Daher ist es in charSequence möglich, einen IntStream zu erhalten, der entweder chars oder codePoints darstellt. Bevor wir zu ihnen übergehen, sehen wir uns ein Beispiel an, um die Zweckmäßigkeit dieses Ansatzes zu veranschaulichen. Lassen Sie uns den Online-Java-Compiler Tutorialspoint verwenden und den Code ausführen:
public static void main(String []args){
        String line = "aaabccdddc";
        System.out.println( line.chars().distinct().count() );
}
Jetzt können Sie auf diese einfache Weise eine Reihe einzigartiger Symbole erhalten.

CodePoints

Also haben wir uns über Zeichen informiert. Nun ist nicht klar, um welche Art von Codepunkten es sich dabei handelt. Das Konzept von codePoint entstand, weil bei der Einführung von Java 16 Bit (ein halbes Int) ausreichten, um ein Zeichen zu kodieren. Daher wird char in Java im UTF-16-Format („Unicode 88“-Spezifikation) dargestellt. Später erschien Unicode 2.0, dessen Konzept darin bestand, ein Zeichen als Ersatzpaar (2 Zeichen) darzustellen. Dadurch konnten wir den Bereich möglicher Werte auf einen int-Wert erweitern. Weitere Einzelheiten finden Sie unter stackoverflow: „ Ein Zeichen mit einem Codepunkt vergleichen? “ UTF-16 wird auch im JavaDoc für Character erwähnt . Dort heißt es im JavaDoc: Es In this representation, supplementary characters are represented as a pair of char values, the first from the high-surrogates range, (\uD800-\uDBFF), the second from the low-surrogates range (\uDC00-\uDFFF). ist ziemlich schwierig (und vielleicht sogar unmöglich), dies in Standardalphabeten zu reproduzieren. Aber die Symbole enden nicht mit Buchstaben und Zahlen. In Japan haben sie sich etwas so schwer zu kodierendes Emoji ausgedacht – die Sprache der Ideogramme und Emoticons. Auf Wikipedia gibt es dazu einen interessanten Artikel: „ Emoji “. Suchen wir ein Beispiel für ein Emoji, zum Beispiel dieses: „ Emoji Ghost “. Wie wir sehen können, wird dort sogar der gleiche CodePoint angezeigt (Wert = U+1F47B). Die Angabe erfolgt im Hexadezimalformat. Wenn wir in eine Dezimalzahl umrechnen, erhalten wir 128123. Das sind mehr als 16 Bits zulässig (d. h. mehr als 65535). Kopieren wir es:
Strings in Java (Klasse java.lang.String) – 2
Leider unterstützt die JavaRush-Plattform solche Zeichen im Text nicht. Daher müssen Sie im folgenden Beispiel einen Wert in String einfügen. Deshalb werden wir jetzt einen einfachen Test verstehen:
public static void main(String []args){
	    String emojiString = "Вставте сюда эмоджи через ctrl+v";
	    //На один emojiString приходится 2 чара (т.к. не влезает в 16 бит)
	    System.out.println(emojiString.codePoints().count()); //1
	    System.out.println(emojiString.chars().count()); //2
}
Wie Sie sehen, entspricht in diesem Fall 1 CodePoint 2 Zeichen. Das ist die Magie.

Charakter

Wie wir oben gesehen haben, bestehen Strings in Java aus char. Mit einem primitiven Typ können Sie einen Wert speichern, aber ein Wrapper java.lang.Characterüber einem primitiven Typ ermöglicht Ihnen, viele nützliche Dinge mit diesem Symbol zu tun. Beispielsweise können wir einen String in Großbuchstaben umwandeln:
public static void main(String[] args) {
    String line = "организация объединённых наций";
    char[] chars = line.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        if (i == 0 || chars[i - 1] == ' ') {
            chars[i] = Character.toUpperCase(chars[i]);
        }
    }
    System.out.println(new String(chars));
}
Nun, verschiedene interessante Dinge: isAlphabetic(), isLetter(), isSpaceChar(), isDigit(), isUpperCase(), isMirrored()(zum Beispiel Klammern. '(' hat ein Spiegelbild ')').

String-Pool

Strings in Java sind unveränderlich, also konstant. Dies wird auch im JavaDoc der java.lang.String- Klasse selbst angegeben . Zweitens, und das ist auch sehr wichtig, können Strings als Literale angegeben werden:
String literalString = "Hello, World!";
String literalString = "Hello, World!";
Das heißt, jede Zeichenfolge in Anführungszeichen ist, wie oben erwähnt, tatsächlich ein Objekt. Und das wirft die Frage auf: Gibt es eine Möglichkeit, sicherzustellen, dass die Zeichenfolgen nicht jedes Mal erstellt werden, wenn wir Zeichenfolgen so oft verwenden und diese häufig identisch sein können (z. B. der Text „Fehler“ oder „Erfolgreich“)? Übrigens haben wir immer noch Maps, bei denen der Schlüssel ein String sein kann. Dann können wir auf keinen Fall dieselben Zeichenfolgen als unterschiedliche Objekte verwenden, sonst können wir das Objekt nicht aus der Map abrufen. Java-Entwickler dachten, dachten und kamen auf String Pool. Dies ist ein Ort, an dem Zeichenfolgen gespeichert werden. Sie können ihn als Zeichenfolgencache bezeichnen. Dort landen nicht alle Zeilen selbst, sondern nur die Zeilen, die im Code durch ein Literal angegeben werden. Sie können selbst eine Linie zum Pool hinzufügen, aber dazu später mehr. Im Speicher haben wir also irgendwo diesen Cache. Eine berechtigte Frage: Wo befindet sich dieser Pool? Die Antwort darauf finden Sie auf stackoverflow: „ Wo befindet sich Javas String-Konstantenpool, der Heap oder der Stack?“ " Es befindet sich im Heap-Speicher, in einem speziellen Poolbereich für Laufzeitkonstanten. Der Runtime-Konstantenpool wird zugewiesen, wenn eine Klasse oder Schnittstelle von der virtuellen Maschine aus dem Methodenbereich erstellt wird – einem speziellen Bereich im Heap, auf den alle Threads innerhalb der Java Virtual Machine Zugriff haben. Was gibt uns der String-Pool? Dies hat mehrere Vorteile:
  • Objekte desselben Typs werden nicht erstellt
  • Der Vergleich per Referenz ist schneller als der zeichenweise Vergleich per Gleichheit
Was aber, wenn wir das erstellte Objekt in diesen Cache legen möchten? Dann haben wir eine spezielle Methode: String.intern Diese Methode fügt dem String-Pool einen String hinzu. Es ist erwähnenswert, dass es sich hierbei nicht nur um eine Art Cache in Form eines Arrays handelt (wie bei Ganzzahlen). Die interne Methode wird als „nativ“ angegeben. Dies bedeutet, dass die Methode selbst in einer anderen Sprache (meist C++) implementiert ist. Bei grundlegenden Java-Methoden können auf JVM-Ebene verschiedene weitere Optimierungen vorgenommen werden. Im Allgemeinen wird hier Magie passieren. Es ist interessant, den folgenden Beitrag über Praktikanten zu lesen: https://habr.com/post/79913/#comment_2345814 Und es scheint eine gute Idee zu sein. Aber wie wird sich das auf uns auswirken? Aber es wird wirklich Auswirkungen haben)
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal");
    System.out.println(test == test2);
}
Wie Sie sehen, sind die Zeilen gleich, aber das Ergebnis ist falsch. Und das alles, weil == nicht nach Wert, sondern nach Referenz vergleicht. Und so funktioniert es:
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test == test2);
}
Bitte beachten Sie, dass wir weiterhin neue Strings erstellen werden. Das heißt, intern gibt uns einen String aus dem Cache zurück, aber der ursprüngliche String, nach dem wir im Cache gesucht haben, wird zur Reinigung verworfen, weil niemand sonst weiß von ihm. Dies ist eindeutig ein unnötiger Ressourcenverbrauch =( Daher sollten Sie Zeichenfolgen immer mit Gleichheitswerten vergleichen, um plötzliche und schwer zu erkennende Fehler so weit wie möglich zu vermeiden.
public static void main(String[] args) {
    String test = "literal";
    String test2 = new String("literal").intern();
    System.out.println(test.equals(test2));
}
Equals führt einen zeichenweisen Zeichenfolgenvergleich durch.

Verkettung

Wie wir uns erinnern, können Zeilen hinzugefügt werden. Und wie wir uns erinnern, sind unsere Fäden unveränderlich. Wie funktioniert es dann? Richtig, es wird eine neue Zeile erstellt, die aus Symbolen der hinzugefügten Objekte besteht. Es gibt eine Million Versionen, wie die Plus-Verkettung funktioniert. Manche Leute denken, dass es jedes Mal ein neues Objekt geben wird, andere denken, dass es etwas anderes geben wird. Aber vielleicht hat nur einer Recht. Und dieser Jemand ist der Javac-Compiler. Nutzen wir den Online-Compiler- Dienst und führen Sie Folgendes aus:
public class HelloWorld {

    public static void main(String[] args) {
        String helloMessage = "Hello, ";
        String target = "World";
        System.out.println(helloMessage + target);
    }

}
Jetzt speichern wir das als Zip-Archiv, entpacken es in ein Verzeichnis und führen es aus: javap –c HelloWorld Und hier erfahren wir alles:
Strings in Java (Klasse java.lang.String) – 3
In einer Schleife ist es natürlich besser, die Verkettung über StringBuilder selbst vorzunehmen. Und das nicht aus irgendeiner Art von Magie, sondern damit der StringBuilder vor dem Zyklus erstellt wird und im Zyklus selbst nur das Anhängen erfolgt. Übrigens gibt es hier noch eine weitere interessante Sache. Es gibt einen ausgezeichneten Artikel: „ String Processing in Java. Teil I: String, StringBuffer, StringBuilder . Viele nützliche Informationen in den Kommentaren. Beispielsweise wird angegeben, dass beim Verketten einer Ansicht eine new StringBuilder().append()...toString()intrinsische Optimierung wirksam ist, die durch die Option -XX:+OptimizeStringConcat reguliert wird, die standardmäßig aktiviert ist. intrinsisch – übersetzt als „intern“. Die JVM handhabt solche Dinge auf besondere Weise und verarbeitet sie als Native, nur ohne die zusätzlichen Kosten von JNI. Lesen Sie mehr: „ Intrinsische Methoden in HotSpot VM “.

StringBuilder und StringBuffer

Wie wir oben gesehen haben, ist StringBuilder ein sehr nützliches Tool. Strings sind unveränderlich, d.h. unveränderlich. Und ich möchte es falten. Daher stehen uns zwei Klassen zur Verfügung: StringBuilder und StringBuffer. Der Hauptunterschied zwischen den beiden besteht darin, dass StringBuffer in JDK1.0 eingeführt wurde, während StringBuilder in Java 1.5 als nicht synchronisierte Version von StringBuffer kam, um den erhöhten Overhead unnötiger Methodensynchronisierung zu vermeiden. Beide Klassen sind Implementierungen der abstrakten Klasse AbstractStringBuilder – eine veränderbare Zeichenfolge. Darin wird ein Array von Charms gespeichert, das gemäß der Regel erweitert wird: value.length * 2 + 2. Standardmäßig beträgt die Größe (Kapazität) von StringBuilder 16.

Vergleichbar

Die Saiten sind vergleichbar, d.h. Implementieren Sie die Methode „compareTo“. Dies erfolgt durch einen zeichenweisen Vergleich. Interessanterweise wird die Mindestlänge aus zwei Zeichenfolgen ausgewählt und eine Schleife darüber ausgeführt. Daher gibt „compareTo“ entweder die Differenz zwischen den int-Werten der ersten nicht übereinstimmenden Zeichen bis zur kleinsten Zeichenfolgenlänge zurück oder die Differenz zwischen den Zeichenfolgenlängen, wenn alle Zeichen innerhalb der minimalen Zeichenfolgenlänge übereinstimmen. Dieser Vergleich wird „lexikographisch“ genannt.

Arbeiten mit Java-Strings

String verfügt über viele nützliche Methoden:
Strings in Java (Klasse java.lang.String) – 4
Es gibt viele Aufgaben für die Arbeit mit Strings. Zum Beispiel auf Coding Bat . Es gibt auch einen Kurs auf Coursera: „ Algorithms on Strings “.

Abschluss

Selbst ein kurzer Überblick über diesen Kurs nimmt beeindruckend viel Platz ein. Und das ist nicht alles. Ich empfehle dringend, sich den Bericht von JPoint 2015 anzusehen: Alexey Shipilev - Catechism java.lang.String
#Wjatscheslaw
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION