Domande e risposte dell'intervista su Java String

1. Introduzione

La classe String è una delle classi più utilizzate in Java, che ha spinto i progettisti del linguaggio a trattarla in modo speciale. Questo comportamento speciale lo rende uno degli argomenti più caldi nelle interviste a Java.

In questo tutorial, esamineremo alcune delle domande dell'intervista più comuni su String .

2. Fondamenti delle corde

Questa sezione è composta da domande che riguardano la struttura interna e la memoria delle String .

Q1. Cos'è una stringa in Java?

In Java, una stringa è rappresentata internamente da una matrice di valori di byte (o valori di caratteri prima di JDK 9).

Nelle versioni fino a Java 8 incluso, una stringa era composta da un array immutabile di caratteri Unicode. Tuttavia, la maggior parte dei caratteri richiede solo 8 bit (1 byte) per rappresentarli invece di 16 bit ( dimensione del carattere ).

Per migliorare il consumo di memoria e le prestazioni, Java 9 ha introdotto le stringhe compatte. Ciò significa che se una stringa contiene solo caratteri a 1 byte, verrà rappresentata utilizzando la codifica Latin-1 . Se una stringa contiene almeno 1 carattere multibyte, verrà rappresentata come 2 byte per carattere utilizzando la codifica UTF-16.

In C e C ++, anche String è un array di caratteri, ma in Java è un oggetto separato con la propria API.

Q2. Come possiamo creare un oggetto stringa in Java ?

java.lang.String definisce 13 modi diversi per creare una stringa . In genere, però, ce ne sono due:

  • Attraverso una stringa letterale:
    String s = "abc";
  • Attraverso la nuova parola chiave:
    String s = new String("abc");

Tutti i valori letterali String in Java sono istanze della classe String .

Q3. String è un tipo primitivo o derivato?

Una String è un tipo derivato poiché ha stato e comportamento. Ad esempio, ha metodi come substring () , indexOf () ed equals (), che le primitive non possono avere.

Ma, dal momento che lo usiamo tutti così spesso, ha alcune caratteristiche speciali che lo fanno sembrare un primitivo:

  • Sebbene le stringhe non siano memorizzate nello stack di chiamate come le primitive, sono memorizzate in una regione di memoria speciale chiamata pool di stringhe
  • Come le primitive, possiamo usare l' operatore + sulle stringhe
  • E ancora, come le primitive, possiamo creare un'istanza di una stringa senza la nuova parola chiave

Q4. Quali sono i vantaggi di stringhe immutabili?

Secondo un'intervista di James Gosling, le stringhe sono immutabili per migliorare le prestazioni e la sicurezza.

E in realtà, vediamo diversi vantaggi nell'avere stringhe immutabili:

  • Il pool di stringhe è possibile solo se le stringhe, una volta create, non vengono mai modificate, in quanto dovrebbero essere riutilizzate
  • Il codice può passare tranquillamente una stringa a un altro metodo , sapendo che non può essere alterato da quel metodo
  • Immutabilmente automaticamente rende questa classe thread-safe
  • Poiché questa classe è thread-safe, non è necessario sincronizzare i dati comuni , il che a sua volta migliora le prestazioni
  • Poiché è garantito che non cambino, il loro codice hash può essere facilmente memorizzato nella cache

Q5. Come viene archiviata una stringa in memoria?

Secondo la specifica JVM, i valori letterali stringa vengono memorizzati in un pool di costanti di runtime, allocato dall'area del metodo della JVM.

Sebbene l'area del metodo faccia parte logicamente della memoria heap, la specifica non determina la posizione, la dimensione della memoria o le politiche di garbage collection. Può essere specifico dell'implementazione.

Questo pool di costanti di runtime per una classe o un'interfaccia viene costruito quando la classe o l'interfaccia viene creata dalla JVM.

Q6. Le stringhe internate sono idonee per la Garbage Collection in Java?

Sì, tutte le stringhe nel pool di stringhe sono idonee per la garbage collection se non ci sono riferimenti dal programma.

Q7. Cos'è lo String Constant Pool?

Il pool di stringhe, noto anche come pool di costanti String o pool interno di String , è una regione di memoria speciale in cui la JVM memorizza le istanze di String .

Ottimizza le prestazioni dell'applicazione riducendo la frequenza e il numero di stringhe allocate:

  • La JVM memorizza solo una copia di una particolare stringa nel pool
  • Quando si crea una nuova stringa , la JVM cerca nel pool una stringa con lo stesso valore
  • Se trovato, la JVM restituisce il riferimento a quella stringa senza allocare memoria aggiuntiva
  • Se non viene trovato, la JVM lo aggiunge al pool (lo internato) e restituisce il suo riferimento

Q8. String è thread-safe? Come?

Le stringhe sono infatti completamente thread-safe perché sono immutabili. Qualsiasi classe immutabile si qualifica automaticamente per la sicurezza dei thread perché la sua immutabilità garantisce che le sue istanze non verranno modificate su più thread.

Ad esempio, se un thread modifica il valore di una stringa, viene creata una nuova stringa invece di modificare quella esistente.

Q9. Per quali operazioni su stringhe è importante fornire una locale?

La classe Locale ci consente di distinguere tra i luoghi culturali e di formattare il nostro contenuto in modo appropriato.

Quando si tratta della classe String , ne abbiamo bisogno durante il rendering di stringhe in formato o quando stringhe con lettere maiuscole o minuscole.

In effetti, se ci dimentichiamo di farlo, possiamo incorrere in problemi di portabilità, sicurezza e usabilità.

Q10. Qual è la codifica dei caratteri sottostante per le stringhe?

According to String's Javadocs for versions up to and including Java 8, Strings are stored in the UTF-16 format internally.

The char data type and java.lang.Character objects are also based on the original Unicode specification, which defined characters as fixed-width 16-bit entities.

Starting with JDK 9, Strings that contain only 1-byte characters use Latin-1 encoding, while Strings with at least 1 multi-byte character use UTF-16 encoding.

3. The String API

In this section, we'll discuss some questions related to the String API.

Q11. How Can We Compare Two Strings in Java? What’s the Difference Between str1 == str2 and str1.Equals(str2)?

We can compare strings in two different ways: by using equal to operator ( == ) and by using the equals() method.

Both are quite different from each other:

  • The operator (str1 == str2) checks for referential equality
  • The method (str1.equals(str2)) checks for lexical equality

Though, it's true that if two strings are lexically equal, then str1.intern() == str2.intern() is also true.

Typically, for comparing two Strings for their content, we should always use String.equals.

Q12. How Can We Split a String in Java?

The String class itself provides us with the String#split method, which accepts a regular expression delimiter. It returns us a String[] array:

String[] parts = "john,peter,mary".split(","); assertEquals(new String[] { "john", "peter", "mary" }, parts);

One tricky thing about split is that when splitting an empty string, we may get a non-empty array:

assertEquals(new String[] { "" }, "".split(","));

Of course, split is just one of many ways to split a Java String.

Q13. What Is Stringjoiner?

StringJoiner is a class introduced in Java 8 for joining separate strings into one, like taking a list of colors and returning them as a comma-delimited string. We can supply a delimiter as well as a prefix and suffix:

StringJoiner joiner = new StringJoiner(",", "[", "]"); joiner.add("Red") .add("Green") .add("Blue"); assertEquals("[Red,Green,Blue]", joiner.toString());

Q14. Difference Between String, Stringbuffer and Stringbuilder?

Strings are immutable. This means that if we try to change or alter its values, then Java creates an absolutely new String.

For example, if we add to a string str1 after it has been created:

String str1 = "abc"; str1 = str1 + "def";

Then the JVM, instead of modifying str1, creates an entirely new String.

However, for most of the simple cases, the compiler internally uses StringBuilder and optimizes the above code.

But, for more complex code like loops, it will create an entirely new String, deteriorating performance. This is where StringBuilder and StringBuffer are useful.

Both StringBuilder and StringBuffer in Java create objects that hold a mutable sequence of characters.StringBuffer is synchronized and therefore thread-safe whereas StringBuilder is not.

Since the extra synchronization in StringBuffer is typically unnecessary, we can often get a performance boost by selecting StringBuilder.

Q15. Why Is It Safer to Store Passwords in a Char[] Array Rather Than a String?

Since strings are immutable, they don't allow modification. This behavior keeps us from overwriting, modifying, or zeroing out its contents, making Strings unsuitable for storing sensitive information.

We have to rely on the garbage collector to remove a string's contents. Moreover, in Java versions 6 and below, strings were stored in PermGen, meaning that once a String was created, it was never garbage collected.

By using a char[] array, we have complete control over that information.We can modify it or wipe it completely without even relying on the garbage collector.

Using char[] over String doesn't completely secure the information; it's just an extra measure that reduces an opportunity for the malicious user to gain access to sensitive information.

Q16. What Does String’s intern() Method Do?

The method intern() creates an exact copy of a String object in the heap and stores it in the String constant pool, which the JVM maintains.

Java automatically interns all strings created using string literals, but if we create a String using the new operator, for example, String str = new String(“abc”), then Java adds it to the heap, just like any other object.

We can call the intern() method to tell the JVM to add it to the string pool if it doesn't already exist there, and return a reference of that interned string:

String s1 = "Baeldung"; String s2 = new String("Baeldung"); String s3 = new String("Baeldung").intern(); assertThat(s1 == s2).isFalse(); assertThat(s1 == s3).isTrue();

Q17. How Can We Convert String to Integer and Integer to String in Java?

The most straightforward approach to convert a String to an Integer is by using Integer#parseInt:

int num = Integer.parseInt("22");

To do the reverse, we can use Integer#toString:

String s = Integer.toString(num);

Q18. What Is String.format() and How Can We Use It?

String#format returns a formatted string using the specified format string and arguments.

String title = "Baeldung"; String formatted = String.format("Title is %s", title); assertEquals("Title is Baeldung", formatted);

We also need to remember to specify the user's Locale, unless we are okay with simply accepting the operating system default:

Locale usersLocale = Locale.ITALY; assertEquals("1.024", String.format(usersLocale, "There are %,d shirts to choose from. Good luck.", 1024))

Q19. How Can We Convert a String to Uppercase and Lowercase?

String implicitly provides String#toUpperCase to change the casing to uppercase.

Though, the Javadocs remind us that we need to specify the user's Locale to ensure correctness:

String s = "Welcome to Baeldung!"; assertEquals("WELCOME TO BAELDUNG!", s.toUpperCase(Locale.US));

Similarly, to convert to lowercase, we have String#toLowerCase:

String s = "Welcome to Baeldung!"; assertEquals("welcome to baeldung!", s.toLowerCase(Locale.UK));

Q20. How Can We Get a Character Array from String?

String provides toCharArray, which returns a copy of its internal char array pre-JDK9 (and converts the String to a new char array in JDK9+):

char[] hello = "hello".toCharArray(); assertArrayEquals(new String[] { 'h', 'e', 'l', 'l', 'o' }, hello);

Q21. How Would We Convert a Java String into a Byte Array?

By default, the method String#getBytes() encodes a String into a byte array using the platform’s default charset.

And while the API doesn't require that we specify a charset, we should in order to ensure security and portability:

byte[] byteArray2 = "efgh".getBytes(StandardCharsets.US_ASCII); byte[] byteArray3 = "ijkl".getBytes("UTF-8");

4. String-Based Algorithms

In this section, we'll discuss some programming questions related to Strings.

Q22. How Can We Check If Two Strings Are Anagrams in Java?

An anagram is a word formed by rearranging the letters of another given word, for example, “car” and “arc”.

To begin, we first check whether both the Strings are of equal length or not.

Then we convert them to char[] array, sort them, and then check for equality.

Q23. How Can We Count the Number of Occurrences of a Given Character in a String?

Java 8 really simplifies aggregation tasks like these:

long count = "hello".chars().filter(ch -> (char)ch == 'l').count(); assertEquals(2, count);

And, there are several other great ways to count the l's, too, including loops, recursion, regular expressions, and external libraries.

Q24. How Can We Reverse a String in Java?

There can be many ways to do this, the most straightforward approach being to use the reverse method from StringBuilder (or StringBuffer):

String reversed = new StringBuilder("baeldung").reverse().toString(); assertEquals("gnudleab", reversed);

Q25. How Can We Check If a String Is a Palindrome or Not?

A palindrome is any sequence of characters that reads the same backward as forward, such as “madam”, “radar” or “level”.

To check if a string is a palindrome, we can start iterating the given string forward and backward in a single loop, one character at a time. The loop exits at the first mismatch.

5. Conclusion

In questo articolo, abbiamo esaminato alcune delle domande più frequenti dell'intervista a String .

Tutti gli esempi di codice usati qui sono disponibili su GitHub.