W3docs

Classe String in Java

Un'analisi approfondita della classe String di Java: progettazione, struttura interna e metodi principali.

String è il tipo di riferimento più utilizzato in Java di gran lunga. Lo hai incontrato fin dal primo giorno — String name = "Ada"; — ed è entrato nel tuo codice senza troppa cerimonia. Questa parte del libro scava sotto quella cerimonia. La classe ha più profondità di quanto la sua superficie suggerisca: un layout interno fisso, una sintassi a livello di linguaggio che gli altri tipi non hanno, un pool di memoria che influisce sull'identità, e una scelta di progettazione deliberata (l'immutabilità) che si propaga attraverso il threading, l'hashing e la sicurezza.

Questo capitolo è la mappa. Il resto della Parte 9 riempie ogni regione.

Che tipo di cosa è una String?

Una String è un normale oggetto Java — java.lang.String, nello stesso package di Object e Integer. È final, quindi non puoi creare sottoclassi, e ogni metodo che "modifica" una stringa restituisce in realtà una nuova stringa. L'originale non viene mai toccata.

String greeting = "hello";
greeting.toUpperCase();          // returns "HELLO" — discarded
System.out.println(greeting);    // still prints "hello"
greeting = greeting.toUpperCase();
System.out.println(greeting);    // now prints "HELLO"

Questa abitudine di restituire-una-nuova-stringa è il fatto più importante sulla classe. È trattata in dettaglio in Immutabilità di String in Java.

Trattamento a livello di linguaggio

Due elementi di sintassi sono riservati a String e non sono estensibili ad altri tipi:

  • Letterali stringa"hello" produce un oggetto String direttamente, senza new. Il compilatore deduplica anche i letterali identici nello string pool.
  • L'operatore + — sovraccaricato per le stringhe: "a" + "b" è "ab". Funzionano anche espressioni miste come "score: " + 42, perché Java converte il lato destro in una String.

Dietro le quinte, i compilatori Java moderni traducono le catene + usando StringBuilder o la StringConcatFactory basata su invokedynamic, quindi raramente è necessario scrivere manualmente la concatenazione. Il compilatore sa cosa fare.

Layout interno

Prima di Java 9, ogni String conteneva un char[] — due byte per carattere indipendentemente dal contenuto. Java 9 ha introdotto le compact strings: l'array di supporto è ora un byte[], più un campo coder di un byte che registra se i byte sono Latin-1 (un byte per carattere) o UTF-16 (due byte). Per il testo che rientra in Latin-1 — la maggior parte del codice, delle configurazioni, degli identificatori, dell'inglese semplice — questo riduce approssimativamente a metà l'occupazione di memoria senza modificare l'API.

Non puoi vedere il campo, non puoi modificarlo, non devi pensarci. Ma è per questo che i programmi che fanno un uso intensivo di stringhe in JDK 9+ usano notevolmente meno heap rispetto a quanto facevano su JDK 8.

Le famiglie di metodi principali

L'API di String è ampia ma si organizza in un gruppo ristretto di famiglie riconoscibili:

Ispezione. length(), isEmpty(), isBlank(), charAt(i), codePointAt(i), hashCode().

Ricerca. indexOf, lastIndexOf, contains, startsWith, endsWith, matches.

Estrazione. substring(start), substring(start, end), chars(), codePoints(), toCharArray().

Trasformazione. toUpperCase(), toLowerCase(), trim(), strip(), replace, replaceAll, replaceFirst, concat.

Suddivisione e unione. split, String.join — trattati in split() e join().

Formattazione. String.format, il metodo di istanza formatted, e l'output in stile printf — trattati in Formattazione delle stringhe.

Confronto. equals, equalsIgnoreCase, compareTo, compareToIgnoreCase, contentEquals — trattati in Confronto tra stringhe.

Conversione. valueOf (statico), toString (di istanza), helper di parsing su Integer, Double, ecc. — trattati in Conversioni di String.

Gli elenchi completi dell'API si trovano nel Javadoc del JDK. La competenza sta nel riconoscere quale famiglia utilizzare, non nel memorizzare ogni overload.

Le stringhe sono sequenze di unità di codice UTF-16

charAt(i) e length() contano le unità di codice UTF-16, non i caratteri Unicode. Per il testo all'interno del Basic Multilingual Plane (la maggior parte degli script comuni), un char = un carattere e la distinzione non ha mai importanza. Per i caratteri supplementari — la maggior parte delle emoji, alcune estensioni CJK, scritture antiche — un singolo carattere visibile all'utente occupa due char, una coppia surrogate.

String emoji = "🙂";
System.out.println(emoji.length());          // 2 — two code units
System.out.println(emoji.codePointCount(0, emoji.length())); // 1 — one code point

Se hai bisogno di iterare per code point Unicode, usa codePoints() o codePointAt. Per la maggior parte dei casi d'uso ASCII — suddivisione di CSV, formattazione di righe di log, confronto di identificatori — length() e charAt sono esattamente quello di cui hai bisogno.

Cugini mutabili: StringBuilder e StringBuffer

Quando è necessario costruire una stringa pezzo per pezzo, l'operatore += ripetuto alloca una nuova String a ogni passaggio. La libreria standard include due compagni mutabili per questo caso:

  • StringBuilder — veloce, single-thread.
  • StringBuffer — stessa API, metodi sincronizzati, utile solo quando più di un thread scrive nello stesso buffer.

Hanno API parallele e capitoli paralleli in questa parte del libro.

Un esempio pratico

Un piccolo esercizio che tocca le famiglie più comuni — ispezione, ricerca, estrazione, trasformazione e conversione — sullo stesso input. Leggi l'output riga per riga; ogni chiamata illustra uno strumento dall'elenco sopra.

java— editable, runs on the server

L'ultima riga è la conclusione. Dopo ogni trasformazione che abbiamo usato, line è byte-identica al letterale con cui abbiamo iniziato — la prova che il modello restituire-una-nuova-stringa è reale, non solo una nota nella documentazione.

Cosa c'è dopo

Le stringhe vengono fornite con un modello di memoria unico nella libreria standard: i letterali identici condividono l'archiviazione, e puoi inserire stringhe arbitrarie in quel pool condiviso con una singola chiamata al metodo. Continua con Java String pool.

Pratica

Pratica
Quale affermazione sulla classe `String` di Java è vera?
Quale affermazione sulla classe `String` di Java è vera?
Was this page helpful?