Java String interview questions, with answers
String is the most-asked class in Java interviews, because it sits where the language's rules meet: it is an object that behaves like a value, the compiler gives it special syntax, and the JVM keeps a pool of it. The questions follow from that — what == really compares, what the pool holds, why a String can never change, and why building one in a loop can be slow. Every answer below comes with code, and every output shown was produced by compiling and running it.
The questions start with comparison and immutability, then move on to building, splitting and checking strings efficiently. Then take the free Java diagnostic — ten questions across every Java topic in the bank — to see which of these you can explain but not yet predict.
The questions, with answers
1.What is the difference between == and equals() for Java strings?
In short: == checks whether two references point to the same object, while equals() compares the characters, so string contents must always be compared with equals().
String is a reference type, so == compares object identity, not text. Two literals with the same text are usually == because the JVM keeps one pooled object per literal, which is why == appears to work in small tests and then fails for strings built at run time — read from input, returned by substring, or joined from a variable, as below. This page's sample asks exactly this. equals() compares character by character; equalsIgnoreCase() ignores case; compareTo() orders strings by UTF-16 code unit, so every uppercase English letter sorts before every lowercase one. When one side may be null, write the literal first, as in "yes".equals(answer), or use Objects.equals(a, b), which handles null on either side.
String x = "pune"; String y = "pu"; String z = y + "ne"; System.out.println(x == z); // false boolean e = x.equals(z); System.out.println(e); // true
2.What is the Java string pool, and what does intern() do?
In short: The pool is a JVM-wide table of unique String objects holding every literal and compile-time constant; intern() returns the pooled copy of a string, adding it first if it is missing.
Because strings are immutable, every occurrence of the same literal can safely share one object, and the pool, on the heap since Java 7, is where those canonical copies live. Compile-time constants are pooled too: a concatenation of literals, or of final String variables initialised with literals, is folded into one literal by the compiler, which is why the first comparison below is true. A string built at run time from an ordinary variable is a new object, unless you call intern(), which returns the canonical instance. new String("text") always creates a new object even though its argument is pooled, which is why it is almost never worth writing. Interning can save memory for many repeated values, but code should still compare with equals().
final String a = "a"; String b = "a"; String s1 = a + "b"; String s2 = b + "b"; System.out.println(s1 == "ab"); // true System.out.println(s2 == "ab"); // false String s3 = s2.intern(); System.out.println(s3 == "ab"); // true
3.Why are strings immutable in Java?
In short: So they can be shared safely: the pool, security checks, thread safety and cached hash codes all rely on a String never changing, at the cost of a new object for every modification.
Once created, a String's characters never change; methods such as toUpperCase(), trim() and replace() return a new String and leave the original alone. The design has four payoffs interviewers expect you to name. Sharing: the pool can hand the same object to every piece of code that uses a literal. Security: a file path or class name checked by one piece of code cannot be altered afterwards by another. Thread safety: an immutable object can be shared between threads without locking. Hashing: a String caches its hash code, and a String key in a HashMap cannot change under the map. The everyday bug is calling one of those methods and ignoring its result, as the first two lines below do; the fix is to assign the result.
String c = " Delhi "; c.trim(); System.out.println(c.length()); // 7 c = c.trim(); System.out.println(c.length()); // 5
4.What is the difference between String, StringBuilder and StringBuffer?
In short: String is immutable; StringBuilder is a mutable buffer for building text and is not synchronized; StringBuffer is the older synchronized version, rarely needed today.
When text is built in steps, in a loop or piece by piece from data, a StringBuilder appends into one growing buffer, while repeated += on a String copies the whole string every time, which makes a loop of n appends O(n²). StringBuffer has the same methods, but every one is synchronized, which costs time and rarely helps, because a string under construction is almost never shared between threads. For a single expression such as "Hi " + name + "!", plain + is fine: the compiler already turns it into efficient code. StringBuilder also offers reverse(), insert(), deleteCharAt() and setLength(), which is why it appears in answers to 'reverse a string' and 'join with commas' questions.
var sb = new StringBuilder(); for (int i = 1; i <= 3; i++) sb.append(i).append(','); sb.setLength(sb.length() - 1); System.out.println(sb); // 1,2,3 sb.reverse(); System.out.println(sb); // 3,2,1
5.How is + evaluated when a String is mixed with numbers in Java?
In short: Left to right, one pair at a time: numbers are added until the first String operand appears, and from then on every + concatenates, so parenthesise any sum you want printed as a number.
+ is left-associative, and each + decides its meaning from its own two operands: if either is a String, it concatenates, converting the other with String.valueOf; otherwise it adds. An expression can therefore change meaning partway through, which is why a label followed by a sum needs parentheses, as in "Sum: " + (a + b). The same rule applies to char, which is numeric until it meets a String, and to a null reference, which concatenates as the text null instead of throwing. For more than two or three pieces, String.format("%d items", n), or a text block for multi-line text, is easier to read than a chain of +.
int a = 2, b = 3; String x = a + b + "kg"; String y = "kg" + a + b; System.out.println(x); // 5kg System.out.println(y); // kg23 String s = null; System.out.println("v=" + s); // v=null
6.Why is a char[] preferred over a String for storing passwords in Java?
In short: A char[] can be overwritten as soon as the password has been checked, while a String stays in memory, immutable, until the garbage collector reclaims it.
Immutability works against secrets. A String holding a password cannot be wiped: it stays on the heap until garbage collection eventually reclaims it, and anyone who can read a heap dump in the meantime can read the password. A char[] can be cleared with Arrays.fill the moment it has been used, shrinking that window, as below. It is also harder to leak by accident: concatenated into a log message, a char[] appears as a type and hash such as [C@1b6d3586 rather than as the text, while a String prints itself. This is why Console.readPassword() and Swing's JPasswordField.getPassword() return char[]. It narrows the exposure rather than removing it, since the JVM may have copied the data elsewhere.
char[] pw = {'k', 'e', 'y'}; Arrays.fill(pw, '*'); System.out.println(pw); // ***
7.How do split() and substring() behave at the edges in Java?
In short: split() takes a regular expression and drops trailing empty strings, and substring(begin, end) excludes end and throws StringIndexOutOfBoundsException for an index out of range.
split's argument is a regex, so splitting on a dot or a pipe needs escaping, most readably as a character class such as split("[.]"). An unescaped dot matches every character, every piece is empty, and all of them are trailing, so the result is an empty array, as below. Trailing empty strings are removed unless you pass a negative limit, which is why splitting "a,b,," on commas gives two pieces, not four. substring(begin, end) returns the characters from begin up to but not including end, so s.substring(i, i + k) is always k characters long. charAt throws for any index outside 0 to length() - 1, and toCharArray() or chars() is the usual way to walk every character.
var p = "a,b,,".split(","); System.out.println(p.length); // 2 var q = "1.2".split("."); System.out.println(q.length); // 0 String s = "placement"; String t = s.substring(0, 5); System.out.println(t); // place
8.What is the difference between isEmpty() and isBlank() in Java?
In short: isEmpty() is true only for a string of length zero, while isBlank(), added in Java 11, is also true for a string containing nothing but whitespace.
Both are instance methods, so both throw NullPointerException on a null reference; the null check comes first, as in s == null || s.isBlank(), the usual validation test. isEmpty() just tests length() == 0. isBlank() tests whether every character is whitespace as Character.isWhitespace defines it, which covers spaces, tabs and line breaks. Java 11 added strip(), stripLeading() and stripTrailing() alongside it. trim() removes leading and trailing characters up to and including the space character, U+0020, while strip() removes Unicode whitespace, which matters for text containing spaces such as the em space, U+2003, that trim() leaves in place.
String s = " \t "; boolean e = s.isEmpty(); boolean b = s.isBlank(); System.out.println(e); // false System.out.println(b); // true
How the diagnostic asks it
One question from the Java bank, exactly as a sitting would show it. The bank has 4 on strings and 30 across Java.
What does this Java code print?
String a = "hi"; String b = "hi"; String c = new String("hi"); System.out.println((a == b) + " " + (a == c) + " " + a.equals(c));
- 1true true true
- 2true false truecorrect
- 3false false true
- 4true false false
a and b are the same literal, so the compiler and the string pool give them the same object and a == b is true. new String("hi") creates a separate object with the same characters, so a == c is false while a.equals(c), which compares contents, is true. true true true assumes == compares contents. false false true assumes every literal is a separate object. true false false assumes equals() also compares references, which it does only for classes that do not override it; String does.
Measure it
Reading answers tells you what’s true. A diagnostic tells you what you get wrong.
10 Java questions across its topics, easy to hard, about fifteen minutes. You get a readiness figure with the arithmetic shown, the topics you missed named, and a practice set sized for today. Free: 1 diagnostic a month and 15 problems a day. No card.