What is the difference between == and equals() in Java, and what is the String pool?
== checks whether two references point to the same object, while equals() checks whether two objects have the same content (if the class overrides it, as String does). String literals are stored once in the String pool, which is why two identical literals can be == but new String("x") cannot.
Explain it simply
Imagine two IRCTC tickets for the same train, same coach and same date. If you ask "are these the same piece of paper?", that is ==. If you ask "do these tickets say the same thing?", that is equals(). Two separate printouts are different papers but have the same content.
In Java, a variable of an object type holds a reference, which is like an address. == compares the addresses. equals() asks the object itself whether it considers the other one equal, and classes like String answer that by comparing characters.
Example
public class StringCompare {
public static void main(String[] args) {
String a = "tapri";
String b = "tapri";
String c = new String("tapri");
System.out.println(a == b); // prints: true (same pooled object)
System.out.println(a == c); // prints: false (c is a new object on the heap)
System.out.println(a.equals(c)); // prints: true (same characters)
System.out.println(a == c.intern()); // prints: true (intern returns the pooled copy)
}
}How it works
- The String pool: Java keeps one shared copy of each string literal in a special area of the heap called the String pool (or string constant pool). When the code says
"tapri"twice, both variables get the same object. This saves memory and is safe because strings are immutable. new String("tapri")always creates a fresh object on the heap, even if the pool already has"tapri". So==with the literal is false.intern()returns the pooled copy of a string, adding it to the pool if needed.equals()is defined inObject, where the default version is just==.String,Integer,LocalDateand most value-like classes override it to compare content. Your own classes compare references until you overrideequals().
Real-world use
Login checks, comparing a user's input with a coupon code, or matching a city name all need equals(). Strings that come from user input, files, databases or network calls are created at runtime, so they are not pooled automatically and == would usually fail even when the text matches.
Common mistakes
- Using
==to compare strings because it "worked in my test". It worked only because both were literals from the pool. - Calling
input.equals("YES")wheninputcan be null, which throwsNullPointerException. Write"YES".equals(input)orObjects.equals(a, b). - Overriding
equals()without overridinghashCode(). Equal objects must have equal hash codes, orHashMapandHashSetbreak. - Using
==onIntegerobjects. Values from -128 to 127 are cached, so==happens to work there and fails for larger numbers.
What to say in the interview
"== compares references, so it tells me whether two variables point to the very same object. equals() compares logical content when the class overrides it, as String does. String literals go into the String pool, so two identical literals share one object and == returns true, but new String creates a separate object, so == is false while equals() is true. In real code I always compare strings with equals(), and when I override equals() in my own class I also override hashCode()."
Follow-up questions
- Why are strings immutable in Java?
- What is the contract between
equals()andhashCode()? - How many objects does
new String("hello")create? - Why does
Integer a = 127, b = 127; a == bgive true but 128 gives false?
Go deeper
Read these once the basics above feel easy.
String s = new String("hello") can create up to two objects: the literal "hello" in the pool (only if it is not there already, and this happens when the class is loaded and the literal is resolved) and the new heap object. Compile-time constant expressions such as "ta" + "pri" are joined by the compiler, so the result is pooled and == "tapri" is true. If one part is a non-final variable, the concatenation happens at runtime and creates a new, unpooled string. Since Java 7, the String pool lives in the main heap rather than PermGen, so pooled strings can be garbage collected like other objects.