Heim  >  Artikel  >  Java  >  Java-Verbesserung (Dreizehn) -----String

Java-Verbesserung (Dreizehn) -----String

黄舟
黄舟Original
2017-02-10 11:22:301062Durchsuche

Es kann bewiesen werden, dass String-Operationen das häufigste Verhalten in der Computerprogrammierung sind.


1. Saite

Zunächst müssen wir klarstellen, dass String kein grundlegender Datentyp, sondern ein Objekt und ein unveränderliches Objekt ist. Wenn Sie sich den Quellcode ansehen, werden Sie feststellen, dass die String-Klasse endgültig ist (natürlich kann sie nicht vererbt werden), und wenn Sie sich die JDK-Dokumentation ansehen, werden Sie feststellen, dass fast jede Operation, die ein String-Objekt ändert, tatsächlich ein neues String-Objekt erstellt .

Der String ist ein Objekt, daher ist sein Wert vor der Initialisierung null. Hier muss „“, null, new String()“ erwähnt werden zwischen den dreien. null bedeutet, dass die Zeichenfolge noch nicht neu war, was bedeutet, dass der Verweis auf das Objekt noch nicht erstellt wurde und ihm kein Speicherplatz zugewiesen wurde. „“ und new String() zeigen jedoch an, dass es neu war , aber es ist intern leer, wurde aber erstellt. Ein Verweis auf ein Objekt erfordert die Zuweisung von Speicherplatz. Zum Beispiel: Ein leeres Glas, man kann nicht sagen, dass sich nichts darin befindet, da sich darin Luft befindet. Natürlich kann man es auch in ein Vakuum verwandeln, null und „ ", der Unterschied zwischen new String() ist wie Vakuum und Luft.

                                                                                                                                                                                                                                               Wenn dies der Fall ist, wird es nicht erstellt und die Referenz auf das Objekt direkt wieder in den String-Pool eingefügt. Wenn nicht, wird es erstellt und dann in den String-Pool eingefügt und eine Referenz auf das neu erstellte Objekt zurückgegeben . Dieser Mechanismus ist sehr nützlich, da er die Effizienz verbessern und den Speicherplatzverbrauch reduzieren kann (d. h. bei Verwendung von Strings), einem neuen String-Objekt (d. h. String). s = neuer String("aa")).

Die Verwendung von Strings ist nichts anderes als diese Aspekte:

1. String-Vergleich

   equals() ------ Bestimmen Sie, ob der Inhalt gleich ist.

      compareTo() ------ Bestimmen Sie das Größenverhältnis von Zeichenfolgen.

       compareToIgnoreCase(String int) ------Ignorieren Sie beim Vergleich die Groß-/Kleinschreibung von Buchstaben.

                                                                                                                                                

equalsIgnoreCase() ------ Bestimmen Sie, ob die Inhalte identisch sind, und ignorieren Sie dabei die Groß-/Kleinschreibung.

ReagionMatches () ----------------------------- --------- Weitere Informationen finden Sie in der API.

2. String-Suche

charAt(int index ) ------Gibt das Zeichen an der angegebenen Indexposition zurück, der Indexbereich beginnt bei 0.

                                                                                                                                                       .

Indexof (String Str, int FROMINDEX); ----------------------------------- Start, um STR aus dem FROMINDEX-Zeichen der Zeichenfolge abzurufen.

                                                                                                                                                lastIndexOf(String str)------Suchen Sie die Position des letzten Vorkommens.

                                                                                                                                                                               .

starWith(String prefix, int tooffset)-----Testen Sie, ob die Teilzeichenfolge dieser Zeichenfolge ab dem angegebenen Index mit dem angegebenen Präfix beginnt.

starWith(String prefix)------Testen Sie, ob dieser String mit dem angegebenen Präfix beginnt.

               endsWith(String suffix)------Testen Sie, ob diese Zeichenfolge mit dem angegebenen Suffix endet.

3. String-Abfangen

public String subString(int beginIndex)------Gibt einen neuen String zurück, der ein Teilstring dieses Strings ist.

public String subString(int beginIndex, int endIndex)------Der zurückgegebene String ist ein String von beginIndex bis endIndex-1.

4. String-Ersetzung

public String replacement (char oldChar, char newChar).

public String replacement(CharSequence target, CharSequence replacement)------Ersetzen Sie die ursprüngliche etarget-Teilsequenz durch die Ersatzsequenz und geben Sie eine neue Zeichenfolge zurück.

    public String replacementAll(String regex, String replacement)------Verwenden Sie reguläre Ausdrücke, um Zeichenfolgen abzugleichen. Beachten Sie, dass der erste Parameter von replaceAll ein regulärer Ausdruck ist und ich sehr darunter gelitten habe.

5. Weitere Methoden finden Sie in der API


2. StringBuffer

StringBuffer und Strings werden alle zum Speichern von Zeichenfolgen verwendet, aber aufgrund ihrer unterschiedlichen internen Implementierung sind die von ihnen verwendeten Bereiche unterschiedlich. Wenn StringBuffer eine Zeichenfolge verarbeitet, wird keine neue Zeichenfolge generiert Daher ist es hinsichtlich der Speichernutzung besser als String.

Tatsächlich ähneln viele Methoden von StringBuffer denen der String-Klasse, und die Funktionen, die sie darstellen, sind fast identisch, mit der Ausnahme, dass StringBuffer sich selbst ändert Wenn es geändert wird, generiert die String-Klasse ein neues Objekt, was den größten Unterschied zwischen ihnen darstellt.

Gleichzeitig kann StringBuffer nicht mit = initialisiert werden. Es muss eine StringBuffer-Instanz generiert werden, was bedeutet, dass Sie es über seine Konstruktionsmethode initialisieren müssen.

In Bezug auf die Verwendung von StringBuffer liegt der Schwerpunkt mehr auf Änderungen an Zeichenfolgen, z. B. Anhängen, Ändern und Löschen. Die entsprechenden Methoden sind:

 1. append(): Den angegebenen Inhalt an das Ende des aktuellen StringBuffer-Objekts anhängen, ähnlich wie bei der Verbindung von Strings, bei der sich der Inhalt des StringBuffer-Objekts ändert.

2. Einfügen: Diese Methode fügt hauptsächlich Inhalte in das StringBuffer-Objekt ein.

3. Löschen: Diese Methode wird hauptsächlich zum Entfernen des Inhalts im StringBuffer-Objekt verwendet.


3. StringBuilder

StringBuilder ist auch ein veränderbares String-Objekt StringBuffer ist aufgrund seiner Thread-Unsicherheit im Allgemeinen schneller als StringBuffer. Wie StringBuffer sind auch die Hauptoperationen von StringBuider die Anhänge- und Einfügemethoden. Beide Methoden wandeln die angegebenen Daten effektiv in eine Zeichenfolge um und fügen dann die Zeichen dieser Zeichenfolge zum Zeichenfolgengenerator hinzu oder fügen sie ein.

Das Obige stellt nur kurz String, StringBuffer und StringBuilder vor. Tatsächlich sollten wir den Unterschieden, die sie nur sehen, mehr Aufmerksamkeit schenken Durch die Klärung der Unterschiede zwischen ihnen können Sie sie besser nutzen.


  4. Verwenden Sie String, StringBuffer, richtig StringBuilder

Schauen wir uns zunächst die folgende Tabelle an:



Mir ist nicht ganz klar, ob String hier threadsicher ist. Der Grund: String ist unveränderlich, also ist es unmöglich, seinen Wert durch irgendeine Operation zu ändern. Es ist schwer zu sagen, ob es Thread-Sicherheit gibt. Wenn Sie jedoch darauf bestehen, dass Threads sicher sind, ist der Inhalt immer sicher, da er unveränderlich ist.

Da String bei jeder Änderung ein neues Objekt generieren muss, ist es am besten, StringBuffer oder StringBuilder für häufig benötigte Zeichenfolgen zu wählen Um ihren Inhalt zu ändern, wird jede Operation am StringBuffer-Objekt selbst ausgeführt und es werden keine neuen Objekte generiert. Daher eignet sich StringBuffer besonders für Situationen, in denen sich der String-Inhalt häufig ändert.

Aber nicht alle String-String-Operationen sind langsamer als StringBuffer. In einigen Sonderfällen wird die String-String-Verkettung von der JVM in die StringBuilder-Objektverkettung analysiert In diesem Fall ist String schneller als StringBuffer. Zum Beispiel:

String name = „I“ + „am“ + „chenssy“ ;

StringBuffer name = new StringBuffer(“I „).append(“ am „).append(“ chenssy „);

 Für diese beiden Methode werden Sie feststellen, dass die erste Methode viel schneller ist als die zweite Methode und der Vorteil von StringBuffer hier verloren geht. Der wahre Grund ist, dass die JVM tatsächlich einige Optimierungen vorgenommen hat: String name = „I“ + „am“ + „chenssy“; Für die JVM dauert es wirklich keine Zeit. Wenn wir jedoch ein String-Objekt hinzufügen, erstellt die JVM das String-Objekt gemäß der ursprünglichen Spezifikation.

Die Szenarien, in denen diese drei verwendet werden, sind wie folgt zusammengefasst (Referenz: „Qualitätscode schreiben: 151 Vorschläge zur Verbesserung von Java-Programmen“):

1, String: Sie können die String-Klasse in Situationen verwenden, in denen die Zeichenfolge nicht häufig geändert wird, z. B. bei der Deklaration von Konstanten, einer kleinen Anzahl variabler Operationen usw.

2. StringBuffer: Wenn Sie häufig String-Operationen (Spleißen, Ersetzen, Löschen usw.) durchführen und in einer Multithread-Umgebung ausführen, können Sie dies in Betracht ziehen Verwenden Sie StringBuffer, z. B. XML-Analyse, HTTP-Parameteranalyse und -Kapselung usw.

3. StringBuilder: Wenn Sie häufig String-Operationen (Spleißen, Ersetzen, Löschen usw.) durchführen und in einer Multithread-Umgebung ausführen, können Sie dies in Betracht ziehen Verwenden Sie StringBuffer, z. B. zum Zusammenstellen von SQL-Anweisungen, JSON-Kapselung usw. (Anscheinend verwende ich auch |StringBuffer für diese beiden).

Weitere Informationen zu den Unterschieden zwischen ihnen finden Sie unter: http://www.php.cn/. Ich werde keine unnötige unnötige unnötige Aufregung hinzufügen.

 5. String-Spleißmethode

Für Strings müssen wir sie oft zusammenstellen. In Java wurden drei Assemblermethoden hinzugefügt: die Methoden +, concat() und append(). Was ist der Unterschied zwischen diesen drei? Schauen Sie sich zunächst das folgende Beispiel an:

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";
        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }
        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }
        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");
        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }
        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米



public class StringTest {    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void     */
    public static void main(String[] args) {        //+
        long start_01 = System.currentTimeMillis();
        String a = "a";        for(int i = 0 ; i < 100000 ; i++){
            a += "b";
        }        long end_01 = System.currentTimeMillis();
        System.out.println("  +   所消耗的时间:" + (end_01 - start_01) + "毫米");        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = "c";        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat("d");
        }        long end_02 = System.currentTimeMillis();
        System.out.println("concat所消耗的时间:" + (end_02 - start_02) + "毫米");        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer("e");        for(int i = 0 ; i < 100000 ; i++){
            e.append("d");
        }        long end_03 = System.currentTimeMillis();
        System.out.println("append所消耗的时间:" + (end_03 - start_03) + "毫米");
    }
}------------Output:  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米

Aus den obigen Laufergebnissen können wir ersehen, dass append() am schnellsten ist, gefolgt von concat() und + am langsamsten ist. Bitte sehen Sie sich die folgende Aufschlüsselung an:


Wir wissen früher, dass der Compiler + optimiert, was mit der append()-Methode von StringBuilder verarbeitet wird. Wir wissen, dass die Geschwindigkeit von StringBuilder schneller ist, aber warum läuft er immer noch mit der gleichen Geschwindigkeit? Hauptsächlich, weil der Compiler die Methode append() verwendet, um sie mit toString() anzuhängen und in einen String-String umzuwandeln. Mit anderen Worten, str +="b" entspricht

🎜>str = new StringBuilder(str).append("b").toString();

 

Der Hauptgrund, warum es langsam wird, ist das Mit new StringBuilder () und toString () werden hier 100.000 StringBuilder-Objekte erstellt, die jedes Mal in String konvertiert werden müssen. Ist das nicht langsam?

(2) concat()-Methode zum Spleißen von Zeichenfolgen  

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
    }


Dies ist der Quellcode von concat() , es sieht aus wie eine digitale Kopie, aber weil die Methode so endet: return new String(0, count + otherLen, buf); die Hauptursache für seine Langsamkeit.

(3) append()-Methode zum Spleißen von Zeichenfolgen

public synchronized StringBuffer append(String str) {    super.append(str);        return this;
    }

Die append()-Methode von StringBuffer besteht darin, die append()-Methode der übergeordneten Klasse AbstractStringBuilder direkt zu verwenden Die Methode lautet wie folgt:

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }


Das Array wird verarbeitet und verlängert , und dann kopiert, aber bitte beachten Sie, dass es am Ende keinen neuen String zurückgibt, sondern sich selbst. Mit anderen Worten, während dieser 100.000-maligen Schleife wird kein neues String-Objekt generiert.

Durch die obige Analyse müssen wir die entsprechende String-Splicing-Methode an der entsprechenden Stelle auswählen, es ist jedoch nicht notwendig, append() und concat( zu wählen )-Methode, der Grund dafür ist, dass wir gemäß unseren Programmiergewohnheiten die Verwendung der Methoden append() und concat() nur dann in Betracht ziehen, wenn sie die Effizienz unseres Systems wirklich verbessern können. Gleichzeitig habe ich das wirklich nicht Irgendeine Idee. Habe die concat()-Methode verwendet.

Das Obige ist der Inhalt des Java-Verbesserungskapitels (13)-----String Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn